closing works, so does importing from Prelude!

This commit is contained in:
Scott Richmond 2024-12-11 17:22:37 -05:00
parent 567d3da4be
commit 6a01089973
4 changed files with 39 additions and 21 deletions

View File

@ -1,5 +1,13 @@
base :print! ("Hello from Prelude") & base :print! ("Hello from Prelude")
fn add (x, y) -> base :add (x, y) & I can't figure out why I need this, but I do
& Otherwise the validator won't close over `base`
let base = base
#{add} fn add (x as :number, y as :number) -> base :add (x, y)
fn dec (n as :number) -> base :sub (n, 1)
fn sub (x as :number, y as :number) -> base :sub (x, y)
#{add, dec, sub}

View File

@ -95,11 +95,12 @@ pub fn prelude<'src>() -> Process<'src> {
let mut v6or = Validator::new(p_ast, *p_span, &base_names); let mut v6or = Validator::new(p_ast, *p_span, &base_names);
v6or.validate(); v6or.validate();
// dbg!(&v6or);
let mut base_ctx = Process::<'src> { let mut base_ctx = Process::<'src> {
locals: vec![], locals: base_pkg,
ast: p_ast, ast: p_ast,
prelude: base_pkg, prelude: vec![],
args: Value::Nil,
fn_info: v6or.fn_info, fn_info: v6or.fn_info,
}; };
@ -128,7 +129,6 @@ pub fn prelude<'src>() -> Process<'src> {
locals: vec![], locals: vec![],
ast: &Ast::Nil, ast: &Ast::Nil,
prelude: p_ctx, prelude: p_ctx,
args: Value::Nil,
fn_info: base_ctx.fn_info, fn_info: base_ctx.fn_info,
} }
} }
@ -158,10 +158,12 @@ pub fn run(src: &'static str) {
v6or.validate(); v6or.validate();
dbg!(&v6or); // dbg!(&v6or);
// dbg!(&v6or.fn_info);
let mut proc = prelude(); let mut proc = prelude();
proc.ast = &ast; proc.ast = &ast;
// dbg!(&proc.fn_info);
proc.fn_info.extend(&mut v6or.fn_info.into_iter()); proc.fn_info.extend(&mut v6or.fn_info.into_iter());
let result = proc.eval(); let result = proc.eval();
@ -174,9 +176,16 @@ pub fn run(src: &'static str) {
pub fn main() { pub fn main() {
let src = " let src = "
let bar = :bar fn fib {
fn foo () -> bar (1) -> 1
foo () (2) -> 1
(n) -> add (
fib (dec (n))
fib (sub (n, 2))
)
}
fib (25)
"; ";
run(src); run(src);
// struct_scalpel::print_dissection_info::<value::Value>() // struct_scalpel::print_dissection_info::<value::Value>()

View File

@ -35,7 +35,6 @@ pub struct Process<'src> {
pub locals: Vec<(String, Value<'src>)>, pub locals: Vec<(String, Value<'src>)>,
pub prelude: Vec<(String, Value<'src>)>, pub prelude: Vec<(String, Value<'src>)>,
pub ast: &'src Ast, pub ast: &'src Ast,
pub args: Value<'src>,
pub fn_info: std::collections::HashMap<*const Ast, FnInfo>, pub fn_info: std::collections::HashMap<*const Ast, FnInfo>,
} }
@ -502,16 +501,17 @@ impl<'src> Process<'src> {
Fn(name, clauses, doc) => { Fn(name, clauses, doc) => {
let doc = doc.map(|s| s.to_string()); let doc = doc.map(|s| s.to_string());
let ptr: *const Ast = root; let ptr: *const Ast = root;
dbg!(&root); // dbg!(&root);
dbg!(&ptr); // dbg!(&ptr);
dbg!(&self.fn_info); // dbg!(&self.fn_info);
let info = self.fn_info.get(&ptr).unwrap(); let info = self.fn_info.get(&ptr).unwrap();
let FnInfo::Defined(_, enclosing) = info else { let FnInfo::Defined(_, _, enclosing) = info else {
unreachable!() unreachable!()
}; };
let enclosing = enclosing let enclosing = enclosing
.iter() .iter()
.map(|name| (name.clone(), self.resolve(name).unwrap().clone())) .filter(|binding| binding != name)
.map(|binding| (binding.clone(), self.resolve(binding).unwrap().clone()))
.collect(); .collect();
let the_fn = Value::Fn::<'src>(Rc::new(crate::value::Fn::<'src> { let the_fn = Value::Fn::<'src>(Rc::new(crate::value::Fn::<'src> {
name: name.to_string(), name: name.to_string(),

View File

@ -33,7 +33,7 @@ pub enum Arity {
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum FnInfo { pub enum FnInfo {
Declared, Declared,
Defined(HashSet<Arity>, HashSet<String>), Defined(String, HashSet<Arity>, HashSet<String>),
Unknown, Unknown,
} }
@ -130,7 +130,7 @@ impl<'a> Validator<'a> {
let root = self.ast; let root = self.ast;
match root { match root {
Error => unreachable!(), Error => unreachable!(),
Word(name) | Ast::Splat(name) => { Word(name) | Splat(name) => {
if !self.resolved(name) { if !self.resolved(name) {
self.err(format!("unbound name `{name}`")) self.err(format!("unbound name `{name}`"))
} else { } else {
@ -309,7 +309,7 @@ impl<'a> Validator<'a> {
//TODO: check arities of prelude fns, too //TODO: check arities of prelude fns, too
let fn_binding = self.bound(name); let fn_binding = self.bound(name);
if let Some((_, _, FnInfo::Defined(arities, _))) = fn_binding { if let Some((_, _, FnInfo::Defined(_, arities, _))) = fn_binding {
let num_args = args.len(); let num_args = args.len();
if !match_arities(arities, num_args as u8) { if !match_arities(arities, num_args as u8) {
self.err(format!("arity mismatch: no clause in function `{name}` with {num_args} argument(s)")) self.err(format!("arity mismatch: no clause in function `{name}` with {num_args} argument(s)"))
@ -453,11 +453,12 @@ impl<'a> Validator<'a> {
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() { if self.bound(binding.as_str()).is_some() {
// println!("{name} closing over {binding}");
closed_over.insert(binding.clone()); closed_over.insert(binding.clone());
} }
} }
let info = FnInfo::Defined(arities, closed_over); let info = FnInfo::Defined(name.to_string(), arities, closed_over);
let root_ptr: *const Ast = root; let root_ptr: *const Ast = root;