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 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::<value::Value>()

View File

@ -49,7 +49,7 @@ pub struct 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 {
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,11 +328,18 @@ 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) {
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(_) => (),
};