diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index fc196fae5..00c06c47c 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -158,16 +158,13 @@ fn fe_opt( }) } -pub fn compile_pre_forms( +pub fn compile_from_compileform( allocator: &mut Allocator, runner: Rc, opts: Rc, - pre_forms: &[Rc], + p0: CompileForm, symbol_table: &mut HashMap, ) -> Result { - // Resolve includes, convert program source to lexemes - let p0 = frontend(opts.clone(), pre_forms)?; - let p1 = if opts.frontend_opt() { // Front end optimization fe_opt(allocator, runner.clone(), opts.clone(), p0)? @@ -197,6 +194,25 @@ pub fn compile_pre_forms( codegen(allocator, runner, opts, &p2, symbol_table) } +pub fn compile_pre_forms( + allocator: &mut Allocator, + runner: Rc, + opts: Rc, + pre_forms: &[Rc], + symbol_table: &mut HashMap, +) -> Result { + // Resolve includes, convert program source to lexemes + let p0 = frontend(opts.clone(), pre_forms)?; + + compile_from_compileform( + allocator, + runner, + opts, + p0, + symbol_table + ) +} + pub fn compile_file( allocator: &mut Allocator, runner: Rc, diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index f4901dfd5..e0b4f7da6 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -9,7 +9,7 @@ use clvm_rs::allocator::Allocator; use crate::classic::clvm::__type_compatibility__::{bi_one, bi_zero}; use crate::classic::clvm_tools::stages::stage_0::TRunProgram; -use crate::compiler::clvm::{run, PrimOverride}; +use crate::compiler::clvm::run; use crate::compiler::codegen::codegen; use crate::compiler::compiler::is_at_capture; use crate::compiler::comptypes::{ @@ -135,61 +135,6 @@ pub struct Evaluator { ignore_exn: bool, } -fn compile_to_run_err(e: CompileErr) -> RunFailure { - match e { - CompileErr(l, e) => RunFailure::RunErr(l, e), - } -} - -impl PrimOverride for Evaluator { - fn try_handle( - &self, - head: Rc, - _context: Rc, - tail: Rc, - ) -> Result>, RunFailure> { - let have_args: Vec> = if let Some(args_list) = tail.proper_list() { - args_list - .iter() - .map(|e| Rc::new(BodyForm::Quoted(e.clone()))) - .collect() - } else { - return Ok(None); - }; - - if let SExp::Atom(hl, head_atom) = head.borrow() { - let mut call_args = vec![Rc::new(BodyForm::Value(SExp::Atom( - hl.clone(), - head_atom.clone(), - )))]; - call_args.append(&mut have_args.clone()); - // Primitives can't have tails. - let call_form = Rc::new(BodyForm::Call(head.loc(), call_args, None)); - - for x in self.extensions.iter() { - if let Some(res) = x - .try_eval( - self, - Rc::new(SExp::Nil(head.loc())), - &HashMap::new(), - &head.loc(), - head_atom, - &have_args, - call_form.clone(), - ) - .map_err(compile_to_run_err)? - { - return dequote(head.loc(), res) - .map_err(compile_to_run_err) - .map(Some); - } - } - } - - Ok(None) - } -} - fn select_helper(bindings: &[HelperForm], name: &[u8]) -> Option { for b in bindings.iter() { if b.name() == name { @@ -1383,7 +1328,7 @@ impl<'info> Evaluator { self.prims.clone(), prim, args, - Some(self), + None, Some(PRIM_RUN_LIMIT), ) .map_err(|e| match e { diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index 7e2b38348..d936a8d75 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -251,8 +251,9 @@ fn make_let_bindings( ) -> Result>, CompileErr> { let err = Err(CompileErr( body.loc(), - "Bad binding tail ".to_string() + &body.to_string(), + format!("Bad binding tail {body:?}") )); + eprintln!("make_let_bindings {body}"); match body.borrow() { SExp::Nil(_) => Ok(vec![]), SExp::Cons(_, head, tl) => head @@ -271,7 +272,10 @@ fn make_let_bindings( result.append(&mut rest_bindings); Ok(result) } - _ => err.clone(), + _ => { + eprintln!("crap {body:?}"); + err.clone() + } }) .unwrap_or_else(|| err.clone()), _ => err, diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index 9eae22249..859d8c79b 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -2,31 +2,24 @@ use std::borrow::Borrow; use std::collections::HashMap; use std::rc::Rc; -use clvmr::allocator::Allocator; use num_bigint::ToBigInt; use num_traits::ToPrimitive; use crate::classic::clvm::__type_compatibility__::{bi_one, bi_zero}; -use crate::compiler::clvm::truthy; -use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts}; -use crate::compiler::evaluate::{EvalExtension, Evaluator}; -use crate::compiler::preprocessor::dequote; -use crate::compiler::sexp::{decode_string, SExp}; +use crate::compiler::clvm::PrimOverride; +use crate::compiler::comptypes::{CompileErr, CompilerOpts}; +use crate::compiler::runtypes::RunFailure; +use crate::compiler::sexp::{decode_string, printable, SExp}; use crate::compiler::srcloc::Srcloc; use crate::util::{number_from_u8, Number}; // If the bodyform represents a constant, only match a quoted string. -fn match_quoted_string(body: Rc) -> Result)>, CompileErr> { +fn match_quoted_string(body: Rc) -> Result)>, CompileErr> { let is_string = match body.borrow() { - BodyForm::Quoted(SExp::QuotedString(_, b'x', _)) => None, - BodyForm::Quoted(SExp::QuotedString(al, _, an)) => Some((al.clone(), an.clone())), - BodyForm::Value(SExp::QuotedString(_, b'x', _)) => None, - BodyForm::Value(SExp::QuotedString(al, _, an)) => Some((al.clone(), an.clone())), - BodyForm::Quoted(_) => None, - _ => { - return Ok(None); - } + SExp::QuotedString(_, b'x', _) => None, + SExp::QuotedString(al, _, an) => Some((al.clone(), an.clone())), + _ => None }; if let Some((loc, s)) = is_string { @@ -36,13 +29,11 @@ fn match_quoted_string(body: Rc) -> Result)>, } } -fn match_atom(body: Rc) -> Result)>, CompileErr> { - if let BodyForm::Quoted(SExp::Atom(al, an)) = body.borrow() { +fn match_atom(body: Rc) -> Result)>, CompileErr> { + if let SExp::Atom(al, an) = body.borrow() { Ok(Some((al.clone(), an.clone()))) - } else if let BodyForm::Quoted(_) = body.borrow() { - Err(CompileErr(body.loc(), "atom required".to_string())) } else { - Ok(None) + Err(CompileErr(body.loc(), "atom required".to_string())) } } @@ -51,23 +42,31 @@ enum MatchedNumber { MatchedHex(Srcloc, Vec), } -fn match_number(body: Rc) -> Result, CompileErr> { +fn match_number(body: Rc) -> Result, CompileErr> { match body.borrow() { - BodyForm::Quoted(SExp::Integer(il, n)) => { - Ok(Some(MatchedNumber::MatchedInt(il.clone(), n.clone()))) + SExp::Integer(il, n) => { + return Ok(Some(MatchedNumber::MatchedInt(il.clone(), n.clone()))); } - BodyForm::Quoted(SExp::QuotedString(ql, b'x', b)) => { - Ok(Some(MatchedNumber::MatchedHex(ql.clone(), b.clone()))) + SExp::QuotedString(ql, b'x', b) => { + return Ok(Some(MatchedNumber::MatchedHex(ql.clone(), b.clone()))); } - BodyForm::Quoted(SExp::Nil(il)) => { - Ok(Some(MatchedNumber::MatchedInt(il.clone(), bi_zero()))) + SExp::Atom(al, b) => { + // An atom with unprintable characters is rendered as an integer. + if !printable(&b) { + let to_integer = number_from_u8(&b); + return Ok(Some(MatchedNumber::MatchedInt(al.clone(), to_integer))); + } } - BodyForm::Quoted(_) => Err(CompileErr(body.loc(), "number required".to_string())), - _ => Ok(None), + SExp::Nil(il) => { + return Ok(Some(MatchedNumber::MatchedInt(il.clone(), bi_zero()))); + } + _ => { } } + + Err(CompileErr(body.loc(), "number required".to_string())) } -fn numeric_value(body: Rc) -> Result { +fn numeric_value(body: Rc) -> Result { match match_number(body.clone())? { Some(MatchedNumber::MatchedInt(_, n)) => Ok(n), Some(MatchedNumber::MatchedHex(_, h)) => Ok(number_from_u8(&h)), @@ -75,7 +74,7 @@ fn numeric_value(body: Rc) -> Result { } } -fn usize_value(body: Rc) -> Result { +fn usize_value(body: Rc) -> Result { let n = numeric_value(body.clone())?; if let Some(res) = n.to_usize() { Ok(res) @@ -84,28 +83,6 @@ fn usize_value(body: Rc) -> Result { } } -fn reify_args( - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, - args: &[Rc], -) -> Result>, CompileErr> { - let mut allocator = Allocator::new(); - let mut converted_args = Vec::new(); - for a in args.iter() { - let shrunk = evaluator.shrink_bodyform( - &mut allocator, - prog_args.clone(), - env, - a.clone(), - false, - None, - )?; - converted_args.push(shrunk); - } - Ok(converted_args) -} - /// A container for a function to evaluate in advanced preprocessor macros. /// We use this trait (which is very similar to the extension trait in Evaluator) /// as a definite handler for a specific named form, so optional returns aren't @@ -119,14 +96,9 @@ pub trait ExtensionFunction { #[allow(clippy::too_many_arguments)] fn try_eval( &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, loc: &Srcloc, - name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr>; + args: &[Rc], + ) -> Result, CompileErr>; } struct StringQ {} @@ -144,23 +116,15 @@ impl ExtensionFunction for StringQ { fn try_eval( &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { + args: &[Rc], + ) -> Result, CompileErr> { let res = match match_quoted_string(args[0].clone()) { Ok(Some(_)) => SExp::Integer(loc.clone(), bi_one()), - Ok(None) => { - return Ok(body); - } - Err(_) => SExp::Nil(loc.clone()), + _ => SExp::Nil(loc.clone()), }; - Ok(Rc::new(BodyForm::Quoted(res))) + Ok(Rc::new(res)) } } @@ -179,23 +143,15 @@ impl ExtensionFunction for NumberQ { fn try_eval( &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { + args: &[Rc], + ) -> Result, CompileErr> { let res = match match_number(args[0].clone()) { Ok(Some(_)) => SExp::Integer(loc.clone(), bi_one()), - Ok(None) => { - return Ok(body); - } - Err(_) => SExp::Nil(loc.clone()), + _ => SExp::Nil(loc.clone()), }; - Ok(Rc::new(BodyForm::Quoted(res))) + Ok(Rc::new(res)) } } @@ -214,23 +170,15 @@ impl ExtensionFunction for SymbolQ { fn try_eval( &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { + args: &[Rc], + ) -> Result, CompileErr> { let res = match match_atom(args[0].clone()) { Ok(Some(_)) => SExp::Integer(loc.clone(), bi_one()), - Ok(None) => { - return Ok(body); - } - Err(_) => SExp::Nil(loc.clone()), + _ => SExp::Nil(loc.clone()), }; - Ok(Rc::new(BodyForm::Quoted(res))) + Ok(Rc::new(res)) } } @@ -249,20 +197,15 @@ impl ExtensionFunction for SymbolToString { fn try_eval( &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, _loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { + args: &[Rc], + ) -> Result, CompileErr> { if let Some((loc, value)) = match_atom(args[0].clone())? { - Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString( + Ok(Rc::new(SExp::QuotedString( loc, b'\"', value, - )))) + ))) } else { - Ok(body) + Err(CompileErr(args[0].loc(), "Not a symbol".to_string())) } } } @@ -282,18 +225,13 @@ impl ExtensionFunction for StringToSymbol { fn try_eval( &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, _loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { + args: &[Rc], + ) -> Result, CompileErr> { if let Some((loc, value)) = match_quoted_string(args[0].clone())? { - Ok(Rc::new(BodyForm::Quoted(SExp::Atom(loc, value)))) + Ok(Rc::new(SExp::Atom(loc, value))) } else { - Ok(body) + Err(CompileErr(args[0].loc(), "Not a string".to_string())) } } } @@ -313,14 +251,9 @@ impl ExtensionFunction for StringAppend { fn try_eval( &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, - _loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { + loc: &Srcloc, + args: &[Rc], + ) -> Result, CompileErr> { let mut out_vec = Vec::new(); let mut out_loc = None; for a in args.iter() { @@ -330,14 +263,14 @@ impl ExtensionFunction for StringAppend { } out_vec.append(&mut value); } else { - return Ok(body); + return Err(CompileErr(a.loc(), "not a quoted string".to_string())); } } - Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString( - out_loc.unwrap_or_else(|| body.loc()), + Ok(Rc::new(SExp::QuotedString( + out_loc.unwrap_or_else(|| loc.clone()), b'\"', out_vec, - )))) + ))) } } @@ -356,27 +289,22 @@ impl ExtensionFunction for NumberToString { fn try_eval( &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, _loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { + args: &[Rc], + ) -> Result, CompileErr> { let match_res = match_number(args[0].clone())?; let (use_loc, int_val) = match &match_res { Some(MatchedNumber::MatchedInt(l, i)) => (l.clone(), i.clone()), Some(MatchedNumber::MatchedHex(l, h)) => (l.clone(), number_from_u8(h)), _ => { - return Ok(body); + return Err(CompileErr(args[0].loc(), "Not a number".to_string())); } }; - Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString( + Ok(Rc::new(SExp::QuotedString( use_loc, b'\"', int_val.to_string().as_bytes().to_vec(), - )))) + ))) } } @@ -395,17 +323,12 @@ impl ExtensionFunction for StringToNumber { fn try_eval( &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, loc: &Srcloc, - _name: &[u8], - args: &[Rc], - _body: Rc, - ) -> Result, CompileErr> { + args: &[Rc], + ) -> Result, CompileErr> { if let Some((loc, value)) = match_quoted_string(args[0].clone())? { if let Ok(cvt_bi) = decode_string(&value).parse::() { - Ok(Rc::new(BodyForm::Quoted(SExp::Integer(loc, cvt_bi)))) + Ok(Rc::new(SExp::Integer(loc, cvt_bi))) } else { Err(CompileErr(loc, "bad number".to_string())) } @@ -433,23 +356,16 @@ impl ExtensionFunction for StringLength { fn try_eval( &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, _loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { + args: &[Rc], + ) -> Result, CompileErr> { if let Some((loc, value)) = match_quoted_string(args[0].clone())? { if let Some(len_bi) = value.len().to_bigint() { - Ok(Rc::new(BodyForm::Quoted(SExp::Integer(loc, len_bi)))) - } else { - Err(CompileErr(loc, "Error getting string length".to_string())) + return Ok(Rc::new(SExp::Integer(loc, len_bi))); } - } else { - Ok(body) } + + Err(CompileErr(args[0].loc(), "Error getting string length".to_string())) } } @@ -468,19 +384,14 @@ impl ExtensionFunction for Substring { fn try_eval( &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, _loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { + args: &[Rc], + ) -> Result, CompileErr> { let start_element = usize_value(args[1].clone())?; let end_element = usize_value(args[2].clone())?; match args[0].borrow() { - BodyForm::Quoted(SExp::QuotedString(l, ch, s)) => { + SExp::QuotedString(l, ch, s) => { if start_element > end_element || start_element > s.len() || end_element > s.len() { return Err(CompileErr( l.clone(), @@ -493,221 +404,13 @@ impl ExtensionFunction for Substring { .skip(start_element) .copied() .collect(); - Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString( + Ok(Rc::new(SExp::QuotedString( l.clone(), *ch, result_value, - )))) - } - BodyForm::Quoted(_) => Err(CompileErr(body.loc(), "Not a string".to_string())), - _ => Ok(body), - } - } -} - -struct List {} - -impl List { - fn create() -> Rc { - Rc::new(List {}) - } -} - -impl ExtensionFunction for List { - fn required_args(&self) -> Option { - None - } - - fn try_eval( - &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, - loc: &Srcloc, - _name: &[u8], - args: &[Rc], - _body: Rc, - ) -> Result, CompileErr> { - let mut allocator = Allocator::new(); - let mut res = Rc::new(BodyForm::Quoted(SExp::Nil(loc.clone()))); - for a in args.iter().rev() { - res = Rc::new(BodyForm::Call( - loc.clone(), - vec![ - Rc::new(BodyForm::Value(SExp::Atom(loc.clone(), b"c".to_vec()))), - a.clone(), - res, - ], - // Calls primitive 'c' so no tail. - None, - )); - } - evaluator.shrink_bodyform(&mut allocator, prog_args, env, res, false, None) - } -} - -struct Cons {} - -impl Cons { - fn create() -> Rc { - Rc::new(Cons {}) - } -} - -impl ExtensionFunction for Cons { - fn required_args(&self) -> Option { - Some(2) - } - - fn try_eval( - &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, - loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { - if let (BodyForm::Quoted(a), BodyForm::Quoted(b)) = (args[0].borrow(), args[1].borrow()) { - Ok(Rc::new(BodyForm::Quoted(SExp::Cons( - loc.clone(), - Rc::new(a.clone()), - Rc::new(b.clone()), - )))) - } else { - Ok(body) - } - } -} - -struct First {} - -impl First { - fn create() -> Rc { - Rc::new(First {}) - } -} - -impl ExtensionFunction for First { - fn required_args(&self) -> Option { - Some(1) - } - - fn try_eval( - &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, - loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { - if let BodyForm::Quoted(SExp::Cons(_, a, _)) = args[0].borrow() { - let a_borrowed: &SExp = a.borrow(); - Ok(Rc::new(BodyForm::Quoted(a_borrowed.clone()))) - } else if let BodyForm::Quoted(_) = args[0].borrow() { - Err(CompileErr(loc.clone(), "bad cons in first".to_string())) - } else { - Ok(body) - } - } -} - -struct Rest {} - -impl Rest { - fn create() -> Rc { - Rc::new(Rest {}) - } -} - -impl ExtensionFunction for Rest { - fn required_args(&self) -> Option { - Some(1) - } - - fn try_eval( - &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, - loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { - if let BodyForm::Quoted(SExp::Cons(_, _, b)) = args[0].borrow() { - let a_borrowed: &SExp = b.borrow(); - Ok(Rc::new(BodyForm::Quoted(a_borrowed.clone()))) - } else if let BodyForm::Quoted(_) = args[0].borrow() { - Err(CompileErr(loc.clone(), "bad cons in rest".to_string())) - } else { - Ok(body) - } - } -} - -struct If {} - -impl If { - fn create() -> Rc { - Rc::new(If {}) - } -} - -impl ExtensionFunction for If { - fn want_interp(&self) -> bool { - false - } - - fn required_args(&self) -> Option { - Some(3) - } - - fn try_eval( - &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, - _loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { - let mut allocator = Allocator::new(); - let cond_result = evaluator.shrink_bodyform( - &mut allocator, - prog_args.clone(), - env, - args[0].clone(), - false, - None, - )?; - - if let Ok(unquoted) = dequote(body.loc(), cond_result) { - if truthy(unquoted) { - evaluator.shrink_bodyform( - &mut allocator, - prog_args, - env, - args[1].clone(), - false, - None, - ) - } else { - evaluator.shrink_bodyform( - &mut allocator, - prog_args, - env, - args[2].clone(), - false, - None, - ) + ))) } - } else { - Ok(body.clone()) + _ => Err(CompileErr(args[0].loc(), "Not a string".to_string())), } } } @@ -750,14 +453,44 @@ pub struct PreprocessorExtension { extfuns: HashMap, Rc>, } +fn compile_to_run_err(e: CompileErr) -> RunFailure { + match e { + CompileErr(l, e) => RunFailure::RunErr(l, e), + } +} + +impl PrimOverride for PreprocessorExtension { + fn try_handle( + &self, + head: Rc, + _context: Rc, + tail: Rc, + ) -> Result>, RunFailure> { + eprintln!("running {head} {tail}"); + if let SExp::Atom(hl, head_atom) = head.borrow() { + let have_args: Vec> = + if let Some(args_list) = tail.proper_list() { + args_list.into_iter().map(Rc::new).collect() + } else { + return Ok(None); + }; + + if let Some(extension) = self.extfuns.get(head_atom) { + let res = extension.try_eval(&hl, &have_args) + .map_err(compile_to_run_err)?; + + eprintln!("res = {res}"); + return Ok(Some(res)); + } + } + + Ok(None) + } +} + impl PreprocessorExtension { pub fn new() -> Self { let extfuns = [ - (b"if".to_vec(), If::create()), - (b"list".to_vec(), List::create()), - (b"c".to_vec(), Cons::create()), - (b"f".to_vec(), First::create()), - (b"r".to_vec(), Rest::create()), (b"string?".to_vec(), StringQ::create()), (b"number?".to_vec(), NumberQ::create()), (b"symbol?".to_vec(), SymbolQ::create()), @@ -791,38 +524,3 @@ impl PreprocessorExtension { opts.set_prim_map(Rc::new(new_prim_map_cloned)) } } - -impl EvalExtension for PreprocessorExtension { - fn try_eval( - &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, - loc: &Srcloc, - name: &[u8], - raw_args: &[Rc], - body: Rc, - ) -> Result>, CompileErr> { - if let Some(extfun) = self.extfuns.get(name) { - if let Some(n) = extfun.required_args() { - if raw_args.len() != n { - return Err(CompileErr( - loc.clone(), - format!("{} requires {} args", decode_string(name), n), - )); - } - } - - let args = if extfun.want_interp() { - reify_args(evaluator, prog_args.clone(), env, raw_args)? - } else { - raw_args.to_vec() - }; - Ok(Some(extfun.try_eval( - evaluator, prog_args, env, loc, name, &args, body, - )?)) - } else { - Ok(None) - } - } -} diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index 0dc9042f6..6cff08790 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -10,12 +10,14 @@ use crate::classic::clvm_tools::clvmc::compile_clvm_text_maybe_opt; use crate::classic::clvm_tools::stages::stage_0::{DefaultProgramRunner, TRunProgram}; use crate::compiler::cldb::hex_to_modern_sexp; -use crate::compiler::clvm::convert_from_clvm_rs; +use crate::compiler::clvm; +use crate::compiler::clvm::{convert_from_clvm_rs, truthy}; +use crate::compiler::compiler::compile_from_compileform; use crate::compiler::comptypes::{ - BodyForm, CompileErr, CompilerOpts, HelperForm, IncludeDesc, IncludeProcessType, + BodyForm, CompileErr, CompileForm, CompilerOpts, HelperForm, IncludeDesc, IncludeProcessType, }; use crate::compiler::dialect::KNOWN_DIALECTS; -use crate::compiler::evaluate::{create_argument_captures, dequote, ArgInputs, Evaluator}; +use crate::compiler::evaluate::{create_argument_captures, ArgInputs}; use crate::compiler::frontend::compile_helperform; use crate::compiler::preprocessor::macros::PreprocessorExtension; use crate::compiler::rename::rename_args_helperform; @@ -69,6 +71,22 @@ fn make_defmac_name(name: &[u8]) -> Vec { res } +fn nilize(v: Rc) -> Rc { + if let SExp::Cons(l,a,b) = v.borrow() { + let a_conv = nilize(a.clone()); + let b_conv = nilize(b.clone()); + if Rc::as_ptr(&a_conv) == Rc::as_ptr(&a) && Rc::as_ptr(&b_conv) == Rc::as_ptr(&b) { + v.clone() + } else { + Rc::new(SExp::Cons(l.clone(), a_conv, b_conv)) + } + } else if !truthy(v.clone()) { + Rc::new(SExp::Nil(v.loc())) + } else { + v + } +} + impl Preprocessor { pub fn new(opts: Rc) -> Self { let runner = Rc::new(DefaultProgramRunner::new()); @@ -278,29 +296,35 @@ impl Preprocessor { )?; let ppext = Rc::new(PreprocessorExtension::new()); - let mut eval = Evaluator::new( - ppext.enrich_prims(self.opts.clone()), + let extension: &PreprocessorExtension = ppext.borrow(); + let opts_prims = extension.enrich_prims(self.opts.clone()); + let new_program = CompileForm { + loc: body.loc(), + args: mdata.args.clone(), + include_forms: vec![], + helpers: self.helpers.clone(), + exp: mdata.body.clone(), + }; + let mut symbol_table = HashMap::new(); + let compiled_program = compile_from_compileform( + &mut allocator, self.runner.clone(), - self.helpers.clone(), - ); - eval.add_extension(ppext); - let res = eval.shrink_bodyform( + opts_prims.clone(), + new_program, + &mut symbol_table, + )?; + let res = clvm::run( &mut allocator, - mdata.args.clone(), - ¯o_arg_env, - mdata.body.clone(), - false, + self.runner.clone(), + opts_prims.prim_map(), + Rc::new(compiled_program), + args.clone(), + Some(extension), None, - )?; + ).map(nilize).map_err(|e| CompileErr::from(e))?; - if let Ok(unquoted) = dequote(body.loc(), res) { - return Ok(Some(unquoted)); - } else { - return Err(CompileErr( - body.loc(), - "Failed to fully evaluate macro".to_string(), - )); - } + eprintln!("macro {} {args} => {res}", decode_string(&name)); + return Ok(Some(res)); } } } diff --git a/src/compiler/runtypes.rs b/src/compiler/runtypes.rs index 720822337..c19d5cc45 100644 --- a/src/compiler/runtypes.rs +++ b/src/compiler/runtypes.rs @@ -1,6 +1,7 @@ use std::fmt::Display; use std::rc::Rc; +use crate::compiler::comptypes::CompileErr; use crate::compiler::sexp::SExp; use crate::compiler::srcloc::Srcloc; @@ -27,3 +28,12 @@ impl Display for RunFailure { Ok(()) } } + +impl From for CompileErr { + fn from(item: RunFailure) -> Self { + match item { + RunFailure::RunExn(l, s) => CompileErr(l.clone(), format!("Runtime exception: {s}")), + RunFailure::RunErr(l, s) => CompileErr(l.clone(), format!("Runtime error: {s}")), + } + } +} diff --git a/src/compiler/sexp.rs b/src/compiler/sexp.rs index 8135428e1..93ef4c848 100644 --- a/src/compiler/sexp.rs +++ b/src/compiler/sexp.rs @@ -361,7 +361,7 @@ pub fn decode_string(v: &[u8]) -> String { return String::from_utf8_lossy(v).as_ref().to_string(); } -fn printable(a: &[u8]) -> bool { +pub fn printable(a: &[u8]) -> bool { for ch in a.iter() { if (*ch as char).is_control() || !(*ch as char).is_ascii() { return false; diff --git a/src/tests/compiler/preprocessor.rs b/src/tests/compiler/preprocessor.rs index 9d8947227..4ada850c1 100644 --- a/src/tests/compiler/preprocessor.rs +++ b/src/tests/compiler/preprocessor.rs @@ -325,7 +325,7 @@ fn test_defmac_create_match_form() { (match X ((16 x y) (c 1 (+ x y))) ((3 () b c) c) - ((3 (q . 1) b c) b) + ((3 1 b c) b) (x x) ) )