start testing, fixing
This commit is contained in:
parent
d48a787447
commit
ec38bcdc8c
30
src/main.rs
30
src/main.rs
|
@ -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>()
|
||||||
|
|
|
@ -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,11 +328,18 @@ 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) {
|
||||||
|
if self.bound(binding.as_str()).is_some() {
|
||||||
closed_over.insert(binding.clone());
|
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(_) => (),
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user