start testing, fixing

This commit is contained in:
Scott Richmond 2024-12-10 17:14:26 -05:00
parent d48a787447
commit ec38bcdc8c
2 changed files with 71 additions and 23 deletions

View File

@ -38,6 +38,7 @@
use chumsky::{input::Stream, prelude::*}; use chumsky::{input::Stream, prelude::*};
use rust_embed::Embed; use rust_embed::Embed;
use std::collections::HashMap;
mod spans; mod spans;
@ -135,7 +136,7 @@ pub fn run(src: &'static str) {
let tokens = tokens.unwrap(); let tokens = tokens.unwrap();
let to_parse = tokens.clone(); 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))) .parse(Stream::from_iter(to_parse).map((0..src.len()).into(), |(t, s)| (t, s)))
.into_output_errors(); .into_output_errors();
if !parse_errors.is_empty() { if !parse_errors.is_empty() {
@ -143,22 +144,31 @@ pub fn run(src: &'static str) {
return; return;
} }
let ast = ast.unwrap().0; let (ast, span) = parse_result.unwrap();
let mut ctx = prelude(); let dummy_prelude = vec![];
ctx.ast = *
let result = ctx.eval(); let mut valxor = validator::Validator::new(&ast, span, &dummy_prelude);
match result { valxor.validate();
Ok(result) => println!("{}", result),
Err(LErr { msg, .. }) => println!("Errors!\n{}", msg), 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() { pub fn main() {
let src = " let src = "
add (1, 2) box foo = 42
foo
"; ";
run(src); run(src);
// struct_scalpel::print_dissection_info::<value::Value>() // struct_scalpel::print_dissection_info::<value::Value>()

View File

@ -49,7 +49,7 @@ pub struct Validator<'a> {
} }
impl<'a> Validator<'a> { impl<'a> Validator<'a> {
fn new(ast: &'a mut Ast, span: Span, prelude: &'a Vec<String>) -> Validator<'a> { pub fn new(ast: &'a Ast, span: Span, prelude: &'a Vec<String>) -> Validator<'a> {
Validator { Validator {
locals: vec![], locals: vec![],
prelude, prelude,
@ -99,13 +99,15 @@ impl<'a> Validator<'a> {
self.status.used_bindings.push(name); self.status.used_bindings.push(name);
} }
fn validate(&mut self) { pub fn validate(&mut self) {
let root = self.ast; let root = self.ast;
match root { match root {
Ast::Error => unreachable!(), Ast::Error => unreachable!(),
Ast::Word(name) | Ast::Splat(name) => { Ast::Word(name) | Ast::Splat(name) => {
if !self.resolved(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) => { Ast::Interpolated(parts) => {
@ -113,7 +115,9 @@ impl<'a> Validator<'a> {
if let (StringPart::Word(name), span) = part { if let (StringPart::Word(name), span) = part {
self.span = *span; self.span = *span;
if !self.resolved(name.as_str()) { 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) => { Ast::Box(name, boxed) => {
if self.bound(name).is_some() { if self.bound(name).is_some() {
self.err(format!("box name `{name}` is already bound")); self.err(format!("box name `{name}` is already bound"));
} else {
self.bind(name.to_string());
} }
let (expr, span) = boxed.as_ref(); let (expr, span) = boxed.as_ref();
self.ast = expr; self.ast = expr;
self.span = *span; self.span = *span;
self.validate(); self.validate();
} }
Ast::Let(lhs, rhs) => todo!(), Ast::Let(lhs, rhs) => {
Ast::Match(scrutinee, clauses) => todo!(), 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) => { Ast::FnDeclaration(name) => {
let tailpos = self.status.tail_position; let tailpos = self.status.tail_position;
@ -312,10 +328,17 @@ impl<'a> Validator<'a> {
// add clause arity to arities // 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(); let mut closed_over = HashSet::new();
for binding in self.status.used_bindings.iter().skip(from) { 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); let info = FnInfo::Defined(arities, closed_over);
@ -361,14 +384,29 @@ impl<'a> Validator<'a> {
let in_loop = self.status.in_loop; let in_loop = self.status.in_loop;
self.status.in_loop = true; self.status.in_loop = true;
let (expr, span) = body; // let (expr, span) = body;
self.span = span; // self.span = span;
self.expr = expr; // self.expr = expr;
self.validate(); // self.validate();
self.status.in_loop = in_loop; 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 // terminals can never be invalid
Ast::Nil | Ast::Boolean(_) | Ast::Number(_) | Ast::Keyword(_) | Ast::String(_) => (), Ast::Nil | Ast::Boolean(_) | Ast::Number(_) | Ast::Keyword(_) | Ast::String(_) => (),
}; };