From ec38bcdc8c6fecdb4c9eae7e9cd76499a8a9ea09 Mon Sep 17 00:00:00 2001 From: Scott Richmond Date: Tue, 10 Dec 2024 17:14:26 -0500 Subject: [PATCH] start testing, fixing --- src/main.rs | 30 +++++++++++++++-------- src/validator.rs | 64 ++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 71 insertions(+), 23 deletions(-) diff --git a/src/main.rs b/src/main.rs index 1fa69f2..7e686ea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,6 +38,7 @@ use chumsky::{input::Stream, prelude::*}; use rust_embed::Embed; +use std::collections::HashMap; mod spans; @@ -135,7 +136,7 @@ pub fn run(src: &'static str) { let tokens = tokens.unwrap(); let to_parse = tokens.clone(); - let (ast, parse_errors) = parser() + let (parse_result, parse_errors) = parser() .parse(Stream::from_iter(to_parse).map((0..src.len()).into(), |(t, s)| (t, s))) .into_output_errors(); if !parse_errors.is_empty() { @@ -143,22 +144,31 @@ pub fn run(src: &'static str) { return; } - let ast = ast.unwrap().0; + let (ast, span) = parse_result.unwrap(); - let mut ctx = prelude(); - ctx.ast = * + let dummy_prelude = vec![]; - let result = ctx.eval(); + let mut valxor = validator::Validator::new(&ast, span, &dummy_prelude); - match result { - Ok(result) => println!("{}", result), - Err(LErr { msg, .. }) => println!("Errors!\n{}", msg), - } + valxor.validate(); + + dbg!(valxor); + + // let mut ctx = prelude(); + // ctx.ast = * + + // let result = ctx.eval(); + + // match result { + // Ok(result) => println!("{}", result), + // Err(LErr { msg, .. }) => println!("Errors!\n{}", msg), + // } } pub fn main() { let src = " -add (1, 2) +box foo = 42 +foo "; run(src); // struct_scalpel::print_dissection_info::() diff --git a/src/validator.rs b/src/validator.rs index 8edd8ac..0f30a9f 100644 --- a/src/validator.rs +++ b/src/validator.rs @@ -49,7 +49,7 @@ pub struct Validator<'a> { } impl<'a> Validator<'a> { - fn new(ast: &'a mut Ast, span: Span, prelude: &'a Vec) -> Validator<'a> { + pub fn new(ast: &'a Ast, span: Span, prelude: &'a Vec) -> Validator<'a> { Validator { locals: vec![], prelude, @@ -99,13 +99,15 @@ impl<'a> Validator<'a> { self.status.used_bindings.push(name); } - fn validate(&mut self) { + pub fn validate(&mut self) { let root = self.ast; match root { Ast::Error => unreachable!(), Ast::Word(name) | Ast::Splat(name) => { if !self.resolved(name) { - self.err(format!("unbound name {name}")) + self.err(format!("unbound name `{name}`")) + } else { + self.use_name(name.to_string()) } } Ast::Interpolated(parts) => { @@ -113,7 +115,9 @@ impl<'a> Validator<'a> { if let (StringPart::Word(name), span) = part { self.span = *span; if !self.resolved(name.as_str()) { - self.err(format!("unbound name {name}")) + self.err(format!("unbound name `{name}`")); + } else { + self.use_name(name.to_string()); } } } @@ -276,14 +280,26 @@ impl<'a> Validator<'a> { Ast::Box(name, boxed) => { if self.bound(name).is_some() { self.err(format!("box name `{name}` is already bound")); + } else { + self.bind(name.to_string()); } let (expr, span) = boxed.as_ref(); self.ast = expr; self.span = *span; self.validate(); } - Ast::Let(lhs, rhs) => todo!(), - Ast::Match(scrutinee, clauses) => todo!(), + Ast::Let(lhs, rhs) => { + let (expr, span) = rhs.as_ref(); + self.ast = expr; + self.span = *span; + self.validate(); + } + Ast::Match(scrutinee, clauses) => { + let (expr, span) = scrutinee.as_ref(); + self.ast = expr; + self.span = *span; + self.validate(); + } Ast::FnDeclaration(name) => { let tailpos = self.status.tail_position; @@ -312,10 +328,17 @@ impl<'a> Validator<'a> { // add clause arity to arities } + // this should be right + // we can't bind anything that's already bound, + // even in arg names + // so anything that is already bound and used + // will, of necessity, be closed over + // we don't want to try to close over locals in functions let mut closed_over = HashSet::new(); - for binding in self.status.used_bindings.iter().skip(from) { - closed_over.insert(binding.clone()); + if self.bound(binding.as_str()).is_some() { + closed_over.insert(binding.clone()); + } } let info = FnInfo::Defined(arities, closed_over); @@ -361,14 +384,29 @@ impl<'a> Validator<'a> { let in_loop = self.status.in_loop; self.status.in_loop = true; - let (expr, span) = body; - self.span = span; - self.expr = expr; - self.validate(); + // let (expr, span) = body; + // self.span = span; + // self.expr = expr; + // self.validate(); self.status.in_loop = in_loop; } - Ast::Recur(args) => {} + Ast::Recur(args) => { + if !self.status.in_loop { + self.err("you may only use `recur` in a loop form".to_string()); + } + if !self.status.tail_position { + self.err("you may only use `recur` in tail position".to_string()); + } + + self.status.tail_position = false; + for arg in args { + let (expr, span) = arg; + self.ast = expr; + self.span = *span; + self.validate(); + } + } // terminals can never be invalid Ast::Nil | Ast::Boolean(_) | Ast::Number(_) | Ast::Keyword(_) | Ast::String(_) => (), };