diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index 5d5cf41e..1f446a05 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -464,6 +464,204 @@ pub trait CompilerOpts { ) -> Result; } +/// A trait that simplifies implementing one's own CompilerOpts personality. +/// This specifies to a CompilerOptsDelegator that this object contains a +/// CompilerOpts that it uses for most of what it does, allowing end users +/// to opt into a default implementation of all the methods via +/// CompilerOptsDelegator and override only what's desired. +pub trait HasCompilerOptsDelegation { + /// Get this object's inner CompilerOpts. + fn compiler_opts(&self) -> Rc; + /// Call a function that updates this object's CompilerOpts and use the + /// update our own object with the result. Return the new wrapper. + fn update_compiler_opts) -> Rc>( + &self, + f: F, + ) -> Rc; + + // Defaults. + fn override_filename(&self) -> String { + self.compiler_opts().filename() + } + fn override_code_generator(&self) -> Option { + self.compiler_opts().code_generator() + } + fn override_dialect(&self) -> AcceptedDialect { + self.compiler_opts().dialect() + } + fn override_disassembly_ver(&self) -> Option { + self.compiler_opts().disassembly_ver() + } + fn override_in_defun(&self) -> bool { + self.compiler_opts().in_defun() + } + fn override_stdenv(&self) -> bool { + self.compiler_opts().stdenv() + } + fn override_optimize(&self) -> bool { + self.compiler_opts().optimize() + } + fn override_frontend_opt(&self) -> bool { + self.compiler_opts().frontend_opt() + } + fn override_frontend_check_live(&self) -> bool { + self.compiler_opts().frontend_check_live() + } + fn override_start_env(&self) -> Option> { + self.compiler_opts().start_env() + } + fn override_prim_map(&self) -> Rc, Rc>> { + self.compiler_opts().prim_map() + } + fn override_get_search_paths(&self) -> Vec { + self.compiler_opts().get_search_paths() + } + + fn override_set_dialect(&self, dialect: AcceptedDialect) -> Rc { + self.update_compiler_opts(|o| o.set_dialect(dialect)) + } + fn override_set_search_paths(&self, dirs: &[String]) -> Rc { + self.update_compiler_opts(|o| o.set_search_paths(dirs)) + } + fn override_set_disassembly_ver(&self, ver: Option) -> Rc { + self.update_compiler_opts(|o| o.set_disassembly_ver(ver)) + } + fn override_set_in_defun(&self, new_in_defun: bool) -> Rc { + self.update_compiler_opts(|o| o.set_in_defun(new_in_defun)) + } + fn override_set_stdenv(&self, new_stdenv: bool) -> Rc { + self.update_compiler_opts(|o| o.set_stdenv(new_stdenv)) + } + fn override_set_optimize(&self, opt: bool) -> Rc { + self.update_compiler_opts(|o| o.set_optimize(opt)) + } + fn override_set_frontend_opt(&self, opt: bool) -> Rc { + self.update_compiler_opts(|o| o.set_frontend_opt(opt)) + } + fn override_set_frontend_check_live(&self, check: bool) -> Rc { + self.update_compiler_opts(|o| o.set_frontend_check_live(check)) + } + fn override_set_code_generator(&self, new_compiler: PrimaryCodegen) -> Rc { + self.update_compiler_opts(|o| o.set_code_generator(new_compiler)) + } + fn override_set_start_env(&self, start_env: Option>) -> Rc { + self.update_compiler_opts(|o| o.set_start_env(start_env)) + } + fn override_set_prim_map( + &self, + new_map: Rc, Rc>>, + ) -> Rc { + self.update_compiler_opts(|o| o.set_prim_map(new_map)) + } + fn override_read_new_file( + &self, + inc_from: String, + filename: String, + ) -> Result<(String, Vec), CompileErr> { + self.compiler_opts().read_new_file(inc_from, filename) + } + fn override_compile_program( + &self, + allocator: &mut Allocator, + runner: Rc, + sexp: Rc, + symbol_table: &mut HashMap, + ) -> Result { + self.compiler_opts() + .compile_program(allocator, runner, sexp, symbol_table) + } +} + +impl CompilerOpts for T { + // Defaults. + fn filename(&self) -> String { + self.override_filename() + } + fn code_generator(&self) -> Option { + self.override_code_generator() + } + fn dialect(&self) -> AcceptedDialect { + self.override_dialect() + } + fn disassembly_ver(&self) -> Option { + self.override_disassembly_ver() + } + fn in_defun(&self) -> bool { + self.override_in_defun() + } + fn stdenv(&self) -> bool { + self.override_stdenv() + } + fn optimize(&self) -> bool { + self.override_optimize() + } + fn frontend_opt(&self) -> bool { + self.override_frontend_opt() + } + fn frontend_check_live(&self) -> bool { + self.override_frontend_check_live() + } + fn start_env(&self) -> Option> { + self.override_start_env() + } + fn prim_map(&self) -> Rc, Rc>> { + self.override_prim_map() + } + fn get_search_paths(&self) -> Vec { + self.override_get_search_paths() + } + + fn set_dialect(&self, dialect: AcceptedDialect) -> Rc { + self.override_set_dialect(dialect) + } + fn set_search_paths(&self, dirs: &[String]) -> Rc { + self.override_set_search_paths(dirs) + } + fn set_disassembly_ver(&self, ver: Option) -> Rc { + self.override_set_disassembly_ver(ver) + } + fn set_in_defun(&self, new_in_defun: bool) -> Rc { + self.override_set_in_defun(new_in_defun) + } + fn set_stdenv(&self, new_stdenv: bool) -> Rc { + self.override_set_stdenv(new_stdenv) + } + fn set_optimize(&self, opt: bool) -> Rc { + self.override_set_optimize(opt) + } + fn set_frontend_opt(&self, opt: bool) -> Rc { + self.override_set_frontend_opt(opt) + } + fn set_frontend_check_live(&self, check: bool) -> Rc { + self.override_set_frontend_check_live(check) + } + fn set_code_generator(&self, new_compiler: PrimaryCodegen) -> Rc { + self.override_set_code_generator(new_compiler) + } + fn set_start_env(&self, start_env: Option>) -> Rc { + self.override_set_start_env(start_env) + } + fn set_prim_map(&self, new_map: Rc, Rc>>) -> Rc { + self.override_set_prim_map(new_map) + } + fn read_new_file( + &self, + inc_from: String, + filename: String, + ) -> Result<(String, Vec), CompileErr> { + self.override_read_new_file(inc_from, filename) + } + fn compile_program( + &self, + allocator: &mut Allocator, + runner: Rc, + sexp: Rc, + symbol_table: &mut HashMap, + ) -> Result { + self.override_compile_program(allocator, runner, sexp, symbol_table) + } +} + /// Frontend uses this to accumulate frontend forms, used internally. #[derive(Debug)] pub struct ModAccum { diff --git a/src/tests/classic/stage_2.rs b/src/tests/classic/stage_2.rs index 9ac9aecf..3f269846 100644 --- a/src/tests/classic/stage_2.rs +++ b/src/tests/classic/stage_2.rs @@ -9,7 +9,6 @@ use crate::classic::clvm_tools::binutils::{assemble, assemble_from_ir, disassemb use crate::classic::clvm_tools::clvmc::compile_clvm_text; use crate::classic::clvm_tools::cmds::call_tool; use crate::classic::clvm_tools::ir::reader::read_ir; -use crate::classic::clvm_tools::stages::stage_0::TRunProgram; use crate::classic::clvm_tools::stages::stage_2::compile::{ do_com_prog, get_compile_filename, get_last_path_component, try_expand_macro_for_atom, }; @@ -17,9 +16,9 @@ use crate::classic::clvm_tools::stages::stage_2::helpers::{brun, evaluate, quote use crate::classic::clvm_tools::stages::stage_2::operators::run_program_for_search_paths; use crate::classic::clvm_tools::stages::stage_2::reader::{process_embed_file, read_file}; -use crate::compiler::comptypes::{CompileErr, CompilerOpts, PrimaryCodegen}; -use crate::compiler::dialect::AcceptedDialect; -use crate::compiler::sexp::{decode_string, SExp}; +use crate::compiler::compiler::DefaultCompilerOpts; +use crate::compiler::comptypes::{CompileErr, CompilerOpts, HasCompilerOptsDelegation}; +use crate::compiler::sexp::decode_string; use crate::compiler::srcloc::Srcloc; fn test_expand_macro( @@ -300,90 +299,38 @@ fn test_process_embed_file_as_hex() { assert_eq!(name, b"test-embed-from-hex"); } -#[derive(Clone, Debug)] +#[derive(Clone)] struct TestCompilerOptsPresentsOwnFiles { - filename: String, - files: HashMap, + files: Rc>, + opts: Rc, } impl TestCompilerOptsPresentsOwnFiles { fn new(filename: String, files: HashMap) -> Self { - TestCompilerOptsPresentsOwnFiles { filename, files } + TestCompilerOptsPresentsOwnFiles { + files: Rc::new(files), + opts: Rc::new(DefaultCompilerOpts::new(&filename)), + } } } -impl CompilerOpts for TestCompilerOptsPresentsOwnFiles { - fn filename(&self) -> String { - self.filename.clone() +impl HasCompilerOptsDelegation for TestCompilerOptsPresentsOwnFiles { + fn compiler_opts(&self) -> Rc { + self.opts.clone() } - fn code_generator(&self) -> Option { - None - } - fn dialect(&self) -> AcceptedDialect { - AcceptedDialect::default() - } - fn in_defun(&self) -> bool { - false - } - fn stdenv(&self) -> bool { - false - } - fn optimize(&self) -> bool { - false - } - fn frontend_opt(&self) -> bool { - false - } - fn frontend_check_live(&self) -> bool { - false - } - fn start_env(&self) -> Option> { - None - } - fn disassembly_ver(&self) -> Option { - None - } - fn prim_map(&self) -> Rc, Rc>> { - Rc::new(HashMap::new()) - } - fn get_search_paths(&self) -> Vec { - vec![".".to_string()] - } - fn set_dialect(&self, _dialect: AcceptedDialect) -> Rc { - Rc::new(self.clone()) - } - fn set_search_paths(&self, _dirs: &[String]) -> Rc { - Rc::new(self.clone()) - } - fn set_in_defun(&self, _new_in_defun: bool) -> Rc { - Rc::new(self.clone()) - } - fn set_stdenv(&self, _new_stdenv: bool) -> Rc { - Rc::new(self.clone()) - } - fn set_optimize(&self, _opt: bool) -> Rc { - Rc::new(self.clone()) - } - fn set_frontend_opt(&self, _opt: bool) -> Rc { - Rc::new(self.clone()) - } - fn set_frontend_check_live(&self, _check: bool) -> Rc { - Rc::new(self.clone()) - } - fn set_code_generator(&self, _new_compiler: PrimaryCodegen) -> Rc { - Rc::new(self.clone()) - } - fn set_start_env(&self, _start_env: Option>) -> Rc { - Rc::new(self.clone()) - } - fn set_prim_map(&self, _prims: Rc, Rc>>) -> Rc { - Rc::new(self.clone()) - } - fn set_disassembly_ver(&self, _ver: Option) -> Rc { - Rc::new(self.clone()) + fn update_compiler_opts) -> Rc>( + &self, + f: F, + ) -> Rc { + let new_opts = f(self.opts.clone()); + Rc::new(TestCompilerOptsPresentsOwnFiles { + opts: new_opts, + ..self.clone() + }) } - fn read_new_file( + + fn override_read_new_file( &self, inc_from: String, filename: String, @@ -397,18 +344,6 @@ impl CompilerOpts for TestCompilerOptsPresentsOwnFiles { format!("could not read {filename}"), )) } - fn compile_program( - &self, - _allocator: &mut Allocator, - _runner: Rc, - _sexp: Rc, - _symbol_table: &mut HashMap, - ) -> Result { - Err(CompileErr( - Srcloc::start(&self.filename), - "test object only".to_string(), - )) - } } // Shows that we can inject a compiler opts and have it provide file data. diff --git a/src/tests/compiler/fuzz.rs b/src/tests/compiler/fuzz.rs index 51a5e537..6016d487 100644 --- a/src/tests/compiler/fuzz.rs +++ b/src/tests/compiler/fuzz.rs @@ -5,7 +5,6 @@ use rand::prelude::Distribution; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; use std::borrow::Borrow; -use std::cell::RefCell; use std::collections::{BTreeSet, HashMap}; use std::fmt::Debug; use std::rc::Rc; @@ -15,8 +14,8 @@ use clvmr::Allocator; use crate::classic::clvm_tools::stages::stage_0::{DefaultProgramRunner, TRunProgram}; use crate::compiler::clvm::{convert_to_clvm_rs, run}; use crate::compiler::compiler::{compile_file, DefaultCompilerOpts}; -use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts, PrimaryCodegen}; -use crate::compiler::dialect::{detect_modern, AcceptedDialect}; +use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts, HasCompilerOptsDelegation}; +use crate::compiler::dialect::detect_modern; use crate::compiler::fuzz::{ExprModifier, FuzzChoice, FuzzGenerator, FuzzTypeParams, Rule}; use crate::compiler::prims::primquote; use crate::compiler::sexp::{enlist, extract_atom_replacement, parse_sexp, SExp}; @@ -41,112 +40,33 @@ pub fn compose_sexp(loc: Srcloc, s: &str) -> Rc { #[derive(Clone)] pub struct TestModuleCompilerOpts { opts: Rc, - written_files: Rc>>>, + // Future use. + // written_files: Rc>>>, } impl TestModuleCompilerOpts { pub fn new(opts: Rc) -> Self { TestModuleCompilerOpts { opts: opts, - written_files: Rc::new(RefCell::new(HashMap::new())), + // Future use. + // written_files: Rc::new(RefCell::new(HashMap::new())), } } - - fn new_opts(&self, opts: Rc) -> Rc { - Rc::new(TestModuleCompilerOpts { - opts, - written_files: self.written_files.clone(), - }) - } } -impl CompilerOpts for TestModuleCompilerOpts { - fn filename(&self) -> String { - self.opts.filename() - } - - fn code_generator(&self) -> Option { - self.opts.code_generator() - } - fn dialect(&self) -> AcceptedDialect { - self.opts.dialect() - } - fn in_defun(&self) -> bool { - self.opts.in_defun() - } - fn stdenv(&self) -> bool { - self.opts.stdenv() - } - fn optimize(&self) -> bool { - self.opts.optimize() - } - fn frontend_opt(&self) -> bool { - self.opts.frontend_opt() - } - fn frontend_check_live(&self) -> bool { - self.opts.frontend_check_live() - } - fn start_env(&self) -> Option> { - self.opts.start_env() - } - fn disassembly_ver(&self) -> Option { - self.opts.disassembly_ver() - } - fn prim_map(&self) -> Rc, Rc>> { - self.opts.prim_map() - } - fn get_search_paths(&self) -> Vec { - self.opts.get_search_paths() +impl HasCompilerOptsDelegation for TestModuleCompilerOpts { + fn compiler_opts(&self) -> Rc { + self.opts.clone() } - fn set_dialect(&self, dialect: AcceptedDialect) -> Rc { - self.new_opts(self.opts.set_dialect(dialect)) - } - fn set_search_paths(&self, dirs: &[String]) -> Rc { - self.new_opts(self.opts.set_search_paths(dirs)) - } - fn set_in_defun(&self, new_in_defun: bool) -> Rc { - self.new_opts(self.opts.set_in_defun(new_in_defun)) - } - fn set_stdenv(&self, new_stdenv: bool) -> Rc { - self.new_opts(self.opts.set_stdenv(new_stdenv)) - } - fn set_optimize(&self, opt: bool) -> Rc { - self.new_opts(self.opts.set_optimize(opt)) - } - fn set_frontend_opt(&self, opt: bool) -> Rc { - self.new_opts(self.opts.set_frontend_opt(opt)) - } - fn set_frontend_check_live(&self, check: bool) -> Rc { - self.new_opts(self.opts.set_frontend_check_live(check)) - } - fn set_code_generator(&self, new_compiler: PrimaryCodegen) -> Rc { - self.new_opts(self.opts.set_code_generator(new_compiler)) - } - fn set_start_env(&self, start_env: Option>) -> Rc { - self.new_opts(self.opts.set_start_env(start_env)) - } - fn set_prim_map(&self, prims: Rc, Rc>>) -> Rc { - self.new_opts(self.opts.set_prim_map(prims)) - } - fn set_disassembly_ver(&self, ver: Option) -> Rc { - self.new_opts(self.opts.set_disassembly_ver(ver)) - } - fn read_new_file( + fn update_compiler_opts) -> Rc>( &self, - inc_from: String, - filename: String, - ) -> Result<(String, Vec), CompileErr> { - self.opts.read_new_file(inc_from, filename) - } - fn compile_program( - &self, - allocator: &mut Allocator, - runner: Rc, - sexp: Rc, - symbol_table: &mut HashMap, - ) -> Result { - self.opts - .compile_program(allocator, runner, sexp, symbol_table) + f: F, + ) -> Rc { + let new_opts = f(self.opts.clone()); + Rc::new(TestModuleCompilerOpts { + opts: new_opts, + ..self.clone() + }) } }