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

View File

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

View File

@ -33,7 +33,7 @@ pub enum Arity {
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum FnInfo {
Declared,
Defined(HashSet<Arity>, HashSet<String>),
Defined(String, HashSet<Arity>, HashSet<String>),
Unknown,
}
@ -130,7 +130,7 @@ impl<'a> Validator<'a> {
let root = self.ast;
match root {
Error => unreachable!(),
Word(name) | Ast::Splat(name) => {
Word(name) | Splat(name) => {
if !self.resolved(name) {
self.err(format!("unbound name `{name}`"))
} else {
@ -309,7 +309,7 @@ impl<'a> Validator<'a> {
//TODO: check arities of prelude fns, too
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();
if !match_arities(arities, num_args as u8) {
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();
for binding in self.status.used_bindings.iter().skip(from) {
if self.bound(binding.as_str()).is_some() {
// println!("{name} closing over {binding}");
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;