notes and comments

This commit is contained in:
Scott Richmond 2024-12-26 18:41:54 -05:00
parent ef0ac40dbe
commit 40d4f48878
3 changed files with 27 additions and 6 deletions

View File

@ -229,3 +229,11 @@ struct StackFrame<'a> {
This gives us a way to access everything we need: where to return to, the root of the stack, the chunk (function->chunk), the closures (function->closures).
### 2024-12-26
One particular concern here, which needs some work: recursion is challenging.
In particular, the issue is that if, as I have been planning, a function closes over all its values at the moment it is compiled, the only value type that requires updating is a function. A function can be declared but not yet defined, and then when another function that uses that function is defined, the closed-over value will be to the declaration but not the definition.
One way to handle this, I think is using `std::cell::OnceCell`. Rather than a `RefCell`, `OnceCell` has no runtime overhead. Instead, what happens is you effectively put a `None` in the cell. Then, once you have the value you want to put in there, you call `set` on the `OnceCell`, and it does what it needs to.
This allows for the closures to be closed over right after compilation.

View File

@ -4,6 +4,7 @@ use crate::value::*;
use chumsky::prelude::SimpleSpan;
use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::FromPrimitive;
use std::cell::OnceCell;
use std::rc::Rc;
#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, ToPrimitive)]
@ -434,23 +435,35 @@ impl Chunk {
}
}
Fn(name, body, doc) => {
// first, declare the function
// TODO: or, check if the function has already been declared!
let init_val = Value::Fn(Rc::new(OnceCell::new()));
self.emit_constant(init_val);
self.bind(name);
// compile the function
let mut chunk = Chunk::new(body, self.name, self.src);
chunk.compile();
if crate::DEBUG_COMPILE {
println!("==function: {name}==");
chunk.disassemble();
}
let lfn = crate::value::LFn {
name,
doc: *doc,
chunk,
closed: vec![],
};
let fn_val = Value::Fn(Rc::new(lfn));
self.emit_constant(fn_val);
self.bind(name);
// TODO: close over everything accessed in the function
// TODO: pull the function off the stack, and set the OnceCell.
}
FnDeclaration(name) => {
todo!()
let lfn = Value::Fn(Rc::new(OnceCell::new()));
self.emit_constant(lfn);
self.bind(name);
}
FnBody(clauses) => {
self.emit_op(Op::ResetMatch);

View File

@ -2,7 +2,7 @@ use crate::compiler::Chunk;
use crate::parser::Ast;
use crate::spans::Spanned;
use imbl::{HashMap, Vector};
use std::cell::RefCell;
use std::cell::{OnceCell, RefCell};
use std::rc::Rc;
#[derive(Clone, Debug, PartialEq)]
@ -37,7 +37,7 @@ pub enum Value {
List(Box<Vector<Value>>),
Dict(Box<HashMap<usize, Value>>),
Box(Rc<RefCell<Value>>),
Fn(Rc<LFn>),
Fn(Rc<OnceCell<LFn>>),
}
impl std::fmt::Display for Value {