From ecc7b26b6604eca7cbaf1967b4b1a893d0a42a4f Mon Sep 17 00:00:00 2001 From: Scott Richmond Date: Wed, 11 Dec 2024 18:58:59 -0500 Subject: [PATCH] process now uses spans, for to give panic locations --- src/main.rs | 45 +++++++++------ src/process.rs | 149 ++++++++++++++++--------------------------------- src/value.rs | 2 +- 3 files changed, 75 insertions(+), 121 deletions(-) diff --git a/src/main.rs b/src/main.rs index 5c8b0da..07ffbd7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -63,8 +63,11 @@ use crate::process::*; #[folder = "assets/"] struct Asset; -pub fn prelude<'src>() -> Process<'src> { - let prelude = Asset::get("prelude.ld").unwrap().data.into_owned(); +pub fn prelude<'src>() -> ( + Vec<(String, Value<'src>)>, + std::collections::HashMap<*const Ast, FnInfo>, +) { + let prelude = Asset::get("test_prelude.ld").unwrap().data.into_owned(); // we know for sure Prelude should live through the whole run of the program let leaked = Box::leak(Box::new(prelude)); let prelude = std::str::from_utf8(leaked).unwrap(); @@ -87,19 +90,20 @@ pub fn prelude<'src>() -> Process<'src> { panic!(); } - let (p_ast, p_span) = Box::leak(Box::new(p_ast.unwrap())); + let prelude_parsed = Box::leak(Box::new(p_ast.unwrap())); let base_pkg = base(); let base_names = base_pkg.iter().map(|binding| binding.0.clone()).collect(); - let mut v6or = Validator::new(p_ast, *p_span, &base_names); + let mut v6or = Validator::new(&prelude_parsed.0, prelude_parsed.1, &base_names); v6or.validate(); // dbg!(&v6or); let mut base_ctx = Process::<'src> { locals: base_pkg, - ast: p_ast, + ast: &prelude_parsed.0, + span: prelude_parsed.1, prelude: vec![], fn_info: v6or.fn_info, }; @@ -125,12 +129,7 @@ pub fn prelude<'src>() -> Process<'src> { } }; - Process { - locals: vec![], - ast: &Ast::Nil, - prelude: p_ctx, - fn_info: base_ctx.fn_info, - } + (p_ctx, base_ctx.fn_info) } pub fn run(src: &'static str) { @@ -150,21 +149,28 @@ pub fn run(src: &'static str) { return; } - let (ast, span) = parse_result.unwrap(); + let parsed = parse_result.unwrap(); let dummy_prelude = vec![]; - let mut v6or = Validator::new(&ast, span, &dummy_prelude); + let mut v6or = Validator::new(&parsed.0, parsed.1, &dummy_prelude); v6or.validate(); // dbg!(&v6or); // dbg!(&v6or.fn_info); - let mut proc = prelude(); - proc.ast = * - // dbg!(&proc.fn_info); - proc.fn_info.extend(&mut v6or.fn_info.into_iter()); + let (prelude_ctx, mut prelude_fn_info) = prelude(); + + prelude_fn_info.extend(&mut v6or.fn_info.into_iter()); + + let mut proc = Process { + locals: vec![], + prelude: prelude_ctx, + ast: &parsed.0, + span: parsed.1, + fn_info: prelude_fn_info, + }; let result = proc.eval(); @@ -176,7 +182,10 @@ pub fn run(src: &'static str) { pub fn main() { let src = " - +when { + false -> :false + true -> :true +} "; run(src); // struct_scalpel::print_dissection_info::() diff --git a/src/process.rs b/src/process.rs index 97b92ea..39a618e 100644 --- a/src/process.rs +++ b/src/process.rs @@ -317,14 +317,17 @@ impl<'src> Process<'src> { } } - fn visit(&mut self, node: &'src Spanned) { - self.ast = &node.0; - self.span = node.1; + pub fn visit(&mut self, node: &'src Spanned) -> LResult<'src> { + let (expr, span) = node; + self.ast = expr; + self.span = *span; + self.eval() } pub fn eval(&mut self) -> LResult<'src> { use Ast::*; - let root = self.ast; + let root_node = self.ast; + let root_span = self.span; let result = match self.ast { Nil => Ok(Value::Nil), Boolean(b) => Ok(Value::Boolean(*b)), @@ -346,56 +349,42 @@ impl<'src> Process<'src> { Ok(Value::AllocatedString(Rc::new(interpolated))) } Block(exprs) => { - let parent = self.ast; let to = self.locals.len(); let mut result = Value::Nil; - for (expr, _) in exprs { - self.ast = expr; - result = self.eval()?; + for expr in exprs { + result = self.visit(expr)?; } - self.pop_to(to); - self.ast = parent; + self.locals.truncate(to); Ok(result) } If(cond, if_true, if_false) => { - let parent = self.ast; - self.ast = &cond.0; - let truthy = self.eval()?.bool(); - self.ast = if truthy { &if_true.0 } else { &if_false.0 }; - let result = self.eval(); - self.ast = parent; - result + let truthy = self.visit(cond)?; + let to_visit = if truthy.bool() { if_true } else { if_false }; + self.visit(to_visit) } List(members) => { - let parent = self.ast; let mut vect = Vector::new(); for member in members { - self.ast = &member.0; - if let Ast::Splat(_) = self.ast { - let to_splat = self.eval()?; - match to_splat { + let member_value = self.visit(member)?; + match member.0 { + Ast::Splat(_) => match member_value { Value::List(list) => vect.append(list), _ => { return Err(LErr::new( "only lists may be splatted into lists".to_string(), )) } - } - } else { - vect.push_back(self.eval()?) + }, + _ => vect.push_back(member_value), } } - self.ast = parent; Ok(Value::List(vect)) } Tuple(members) => { - let parent = self.ast; let mut vect = Vec::new(); for member in members { - self.ast = &member.0; - vect.push(self.eval()?); + vect.push(self.visit(member)?); } - self.ast = parent; Ok(Value::Tuple(Rc::new(vect))) } Word(w) | Ast::Splat(w) => { @@ -403,47 +392,35 @@ impl<'src> Process<'src> { Ok(val) } Let(patt, expr) => { - let parent = self.ast; - self.ast = &expr.0; - let val = self.eval()?; + let val = self.visit(expr)?; let result = match self.match_pattern(&patt.0, &val) { Some(_) => Ok(val), None => Err(LErr::new("no match".to_string())), }; - self.ast = parent; result } Placeholder => Ok(Value::Placeholder), Arguments(a) => { - let parent = self.ast; let mut args = vec![]; - for (arg, _) in a.iter() { - self.ast = arg; - let arg = self.eval()?; - args.push(arg); + for arg in a.iter() { + args.push(self.visit(arg)?) } let result = if args.iter().any(|arg| matches!(arg, Value::Placeholder)) { Ok(Value::Args(Rc::new(args))) } else { Ok(Value::Tuple(Rc::new(args))) }; - self.ast = parent; result } Dict(terms) => { - let parent = self.ast; let mut dict = HashMap::new(); for term in terms { - let (term, _) = term; match term { - Ast::Pair(key, value) => { - self.ast = &value.0; - let value = self.eval()?; - dict.insert(*key, value); + (Ast::Pair(key, value), _) => { + dict.insert(*key, self.visit(value)?); } - Ast::Splat(_) => { - self.ast = term; - let resolved = self.eval()?; + (Ast::Splat(_), _) => { + let resolved = self.visit(term)?; let Value::Dict(to_splat) = resolved else { return Err(LErr::new( "cannot splat non-dict into dict".to_string(), @@ -454,60 +431,42 @@ impl<'src> Process<'src> { _ => unreachable!(), } } - self.ast = parent; Ok(Value::Dict(dict)) } LBox(name, expr) => { - let parent = self.ast; - self.ast = &expr.0; - let val = self.eval()?; + let val = self.visit(expr)?; let boxed = Value::Box(name, Rc::new(RefCell::new(val))); self.bind(name.to_string(), &boxed); - self.ast = parent; Ok(boxed) } Synthetic(root, first, rest) => { - let parent = self.ast; - self.ast = &root.0; - let root = self.eval()?; - self.ast = &first.0; - let first = self.eval()?; - let mut curr = self.apply(root, first)?; + let root_val = self.visit(root)?; + let first_val = self.visit(first)?; + let mut curr = self.apply(root_val, first_val)?; for term in rest.iter() { - self.ast = &term.0; - let next = self.eval()?; + let next = self.visit(term)?; curr = self.apply(curr, next)?; } - self.ast = parent; Ok(curr) } When(clauses) => { - let parent = self.ast; for clause in clauses.iter() { let WhenClause(cond, body) = &clause.0 else { unreachable!() }; - self.ast = &cond.0; - if self.eval()?.bool() { - self.ast = &body.0; - let result = self.eval(); - self.ast = parent; - return result; + if self.visit(cond)?.bool() { + return self.visit(body); }; } Err(LErr::new("no match".to_string())) } - Match(value, clauses) => { - let parent = self.ast; - self.ast = &value.0; - let value = self.eval()?; - let result = self.match_clauses(&value, clauses); - self.ast = parent; - result + Match(scrutinee, clauses) => { + let value = self.visit(scrutinee)?; + self.match_clauses(&value, clauses) } Fn(name, clauses, doc) => { let doc = doc.map(|s| s.to_string()); - let ptr: *const Ast = root; + let ptr: *const Ast = root_node; // dbg!(&root); // dbg!(&ptr); // dbg!(&self.fn_info); @@ -531,64 +490,50 @@ impl<'src> Process<'src> { } FnDeclaration(_name) => Ok(Value::Nil), Panic(msg) => { - self.ast = &msg.0; - let msg = self.eval()?; + let msg = self.visit(msg)?; Err(LErr::new(format!("{msg}"))) } Repeat(times, body) => { - let parent = self.ast; - self.ast = ×.0; - let times_num = match self.eval() { + let times_num = match self.visit(times) { Ok(Value::Number(n)) => n as usize, _ => return Err(LErr::new("`repeat` may only take numbers".to_string())), }; - self.ast = &body.0; for _ in 0..times_num { - self.eval()?; + self.visit(body)?; } - self.ast = parent; Ok(Value::Nil) } Do(terms) => { - let parent = self.ast; - self.ast = &terms[0].0; - let mut result = self.eval()?; - for (term, _) in terms.iter().skip(1) { - self.ast = term; - let next = self.eval()?; + let mut result = self.visit(&terms[0])?; + for term in terms.iter().skip(1) { + let next = self.visit(term)?; let arg = Value::Tuple(Rc::new(vec![result])); result = self.apply(next, arg)?; } - self.ast = parent; Ok(result) } Loop(init, clauses) => { - let parent = self.ast; - self.ast = &init.0; - let mut args = self.eval()?; + let mut args = self.visit(init)?; loop { let result = self.match_clauses(&args, clauses)?; if let Value::Recur(recur_args) = result { args = Value::Tuple(Rc::new(recur_args)); } else { - self.ast = parent; return Ok(result); } } } Recur(args) => { - let parent = self.ast; let mut vect = Vec::new(); for arg in args { - self.ast = &arg.0; - vect.push(self.eval()?); + vect.push(self.visit(arg)?); } - self.ast = parent; Ok(Value::Recur(vect)) } _ => unreachable!(), }; - self.ast = root; + self.ast = root_node; + self.span = root_span; result } } diff --git a/src/value.rs b/src/value.rs index d8fb62b..07e671b 100644 --- a/src/value.rs +++ b/src/value.rs @@ -118,7 +118,7 @@ impl fmt::Display for Value<'_> { impl Value<'_> { pub fn bool(&self) -> bool { - matches!(self, Value::Nil | Value::Boolean(false)) + !matches!(self, Value::Nil | Value::Boolean(false)) } }