lots of bugs fixed--upvalues, bindings, stack manipulations, tail calls, etc.
This commit is contained in:
parent
583262f9e8
commit
25a0c62dcf
|
@ -217,6 +217,12 @@ fn map {
|
|||
& }
|
||||
}
|
||||
|
||||
fn add {
|
||||
() -> 0
|
||||
(x) -> x
|
||||
(x, y) -> base :add (x, y)
|
||||
}
|
||||
|
||||
#{
|
||||
& type
|
||||
& coll?
|
||||
|
@ -233,7 +239,8 @@ fn map {
|
|||
& not
|
||||
& tuple?
|
||||
& fn?
|
||||
& rest
|
||||
first
|
||||
rest
|
||||
inc
|
||||
& dec
|
||||
& count
|
||||
|
@ -242,7 +249,8 @@ fn map {
|
|||
& list?
|
||||
& list
|
||||
& first
|
||||
& fold
|
||||
& append
|
||||
fold
|
||||
append
|
||||
map
|
||||
add
|
||||
}
|
||||
|
|
|
@ -422,3 +422,15 @@ https://craftinginterpreters.com/closures.html#flattening-upvalues.
|
|||
I need to study and adapt this exact set of problems.
|
||||
I believe I need to take the strategy he uses with closures being different from functions, etc.
|
||||
So: rework the closures strategy here.
|
||||
|
||||
***
|
||||
|
||||
Closures strategy mostly unfucked.
|
||||
Now I'm having some difficulty with bindings, again?
|
||||
Current situation: still trying to get `map` and `fold` to work properly.
|
||||
The bindings inside of non-trivial functions goes weird.
|
||||
The scope depths are all out of whack.
|
||||
And the stack positions on stuff are also totally weird.
|
||||
One thing: the way we are now resolving upvalues means that nothing should ever reach back further in the stack than the stack base in the vm.
|
||||
So now we'll do all bindings relative to the stack base.
|
||||
UGH.
|
||||
|
|
109
src/base.rs
109
src/base.rs
|
@ -5,10 +5,10 @@ use std::rc::Rc;
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum BaseFn {
|
||||
Nullary(fn() -> Value),
|
||||
Unary(fn(&Value) -> Value),
|
||||
Binary(fn(&Value, &Value) -> Value),
|
||||
Ternary(fn(&Value, &Value, &Value) -> Value),
|
||||
Nullary(&'static str, fn() -> Value),
|
||||
Unary(&'static str, fn(&Value) -> Value),
|
||||
Binary(&'static str, fn(&Value, &Value) -> Value),
|
||||
Ternary(&'static str, fn(&Value, &Value, &Value) -> Value),
|
||||
}
|
||||
|
||||
pub fn eq(x: &Value, y: &Value) -> Value {
|
||||
|
@ -585,57 +585,60 @@ pub fn r#mod(x: &Value, y: &Value) -> Value {
|
|||
|
||||
pub fn make_base() -> Value {
|
||||
let members = vec![
|
||||
("add", Value::BaseFn(BaseFn::Binary(add))),
|
||||
("append", Value::BaseFn(BaseFn::Binary(append))),
|
||||
("assoc", Value::BaseFn(BaseFn::Ternary(assoc))),
|
||||
("at", Value::BaseFn(BaseFn::Binary(at))),
|
||||
("atan_2", Value::BaseFn(BaseFn::Binary(atan_2))),
|
||||
("bool", Value::BaseFn(BaseFn::Unary(r#bool))),
|
||||
("ceil", Value::BaseFn(BaseFn::Unary(ceil))),
|
||||
("chars", Value::BaseFn(BaseFn::Unary(chars))),
|
||||
("concat", Value::BaseFn(BaseFn::Binary(concat))),
|
||||
("cos", Value::BaseFn(BaseFn::Unary(cos))),
|
||||
("count", Value::BaseFn(BaseFn::Unary(count))),
|
||||
("dec", Value::BaseFn(BaseFn::Unary(dec))),
|
||||
("dissoc", Value::BaseFn(BaseFn::Binary(dissoc))),
|
||||
("div", Value::BaseFn(BaseFn::Binary(div))),
|
||||
("doc!", Value::BaseFn(BaseFn::Unary(doc))),
|
||||
("downcase", Value::BaseFn(BaseFn::Unary(downcase))),
|
||||
("eq?", Value::BaseFn(BaseFn::Binary(eq))),
|
||||
("first", Value::BaseFn(BaseFn::Unary(first))),
|
||||
("floor", Value::BaseFn(BaseFn::Unary(floor))),
|
||||
("get", Value::BaseFn(BaseFn::Binary(get))),
|
||||
("gt?", Value::BaseFn(BaseFn::Binary(gt))),
|
||||
("gte?", Value::BaseFn(BaseFn::Binary(gte))),
|
||||
("inc", Value::BaseFn(BaseFn::Unary(inc))),
|
||||
("last", Value::BaseFn(BaseFn::Unary(last))),
|
||||
("list", Value::BaseFn(BaseFn::Unary(list))),
|
||||
("lt?", Value::BaseFn(BaseFn::Binary(lt))),
|
||||
("lte?", Value::BaseFn(BaseFn::Binary(lte))),
|
||||
("mod", Value::BaseFn(BaseFn::Binary(r#mod))),
|
||||
("mult", Value::BaseFn(BaseFn::Binary(mult))),
|
||||
("number", Value::BaseFn(BaseFn::Unary(number))),
|
||||
("add", Value::BaseFn(BaseFn::Binary("add", add))),
|
||||
("append", Value::BaseFn(BaseFn::Binary("append", append))),
|
||||
("assoc", Value::BaseFn(BaseFn::Ternary("assoc", assoc))),
|
||||
("at", Value::BaseFn(BaseFn::Binary("at", at))),
|
||||
("atan_2", Value::BaseFn(BaseFn::Binary("atan_2", atan_2))),
|
||||
("bool", Value::BaseFn(BaseFn::Unary("bool", r#bool))),
|
||||
("ceil", Value::BaseFn(BaseFn::Unary("ceil", ceil))),
|
||||
("chars", Value::BaseFn(BaseFn::Unary("chars", chars))),
|
||||
("concat", Value::BaseFn(BaseFn::Binary("concat", concat))),
|
||||
("cos", Value::BaseFn(BaseFn::Unary("cos", cos))),
|
||||
("count", Value::BaseFn(BaseFn::Unary("count", count))),
|
||||
("dec", Value::BaseFn(BaseFn::Unary("dec", dec))),
|
||||
("dissoc", Value::BaseFn(BaseFn::Binary("dissoc", dissoc))),
|
||||
("div", Value::BaseFn(BaseFn::Binary("div", div))),
|
||||
("doc!", Value::BaseFn(BaseFn::Unary("doc!", doc))),
|
||||
(
|
||||
"downcase",
|
||||
Value::BaseFn(BaseFn::Unary("downcase", downcase)),
|
||||
),
|
||||
("eq?", Value::BaseFn(BaseFn::Binary("eq?", eq))),
|
||||
("first", Value::BaseFn(BaseFn::Unary("first", first))),
|
||||
("floor", Value::BaseFn(BaseFn::Unary("floor", floor))),
|
||||
("get", Value::BaseFn(BaseFn::Binary("get", get))),
|
||||
("gt?", Value::BaseFn(BaseFn::Binary("gt?", gt))),
|
||||
("gte?", Value::BaseFn(BaseFn::Binary("gte?", gte))),
|
||||
("inc", Value::BaseFn(BaseFn::Unary("inc", inc))),
|
||||
("last", Value::BaseFn(BaseFn::Unary("last", last))),
|
||||
("list", Value::BaseFn(BaseFn::Unary("list", list))),
|
||||
("lt?", Value::BaseFn(BaseFn::Binary("lt?", lt))),
|
||||
("lte?", Value::BaseFn(BaseFn::Binary("lte?", lte))),
|
||||
("mod", Value::BaseFn(BaseFn::Binary("mod", r#mod))),
|
||||
("mult", Value::BaseFn(BaseFn::Binary("mult", mult))),
|
||||
("number", Value::BaseFn(BaseFn::Unary("number", number))),
|
||||
("pi", Value::Number(std::f64::consts::PI)),
|
||||
("print!", Value::BaseFn(BaseFn::Unary(print))),
|
||||
("random", Value::BaseFn(BaseFn::Nullary(random))),
|
||||
("range", Value::BaseFn(BaseFn::Binary(range))),
|
||||
("rest", Value::BaseFn(BaseFn::Unary(rest))),
|
||||
("round", Value::BaseFn(BaseFn::Unary(round))),
|
||||
("show", Value::BaseFn(BaseFn::Unary(show))),
|
||||
("sin", Value::BaseFn(BaseFn::Unary(sin))),
|
||||
("slice", Value::BaseFn(BaseFn::Ternary(slice))),
|
||||
("split", Value::BaseFn(BaseFn::Binary(split))),
|
||||
("sqrt", Value::BaseFn(BaseFn::Unary(sqrt))),
|
||||
("print!", Value::BaseFn(BaseFn::Unary("print!", print))),
|
||||
("random", Value::BaseFn(BaseFn::Nullary("random", random))),
|
||||
("range", Value::BaseFn(BaseFn::Binary("range", range))),
|
||||
("rest", Value::BaseFn(BaseFn::Unary("rest", rest))),
|
||||
("round", Value::BaseFn(BaseFn::Unary("round", round))),
|
||||
("show", Value::BaseFn(BaseFn::Unary("show", show))),
|
||||
("sin", Value::BaseFn(BaseFn::Unary("sin", sin))),
|
||||
("slice", Value::BaseFn(BaseFn::Ternary("slice", slice))),
|
||||
("split", Value::BaseFn(BaseFn::Binary("split", split))),
|
||||
("sqrt", Value::BaseFn(BaseFn::Unary("sqrt", sqrt))),
|
||||
("sqrt_2", Value::Number(std::f64::consts::SQRT_2)),
|
||||
("store!", Value::BaseFn(BaseFn::Binary(store))),
|
||||
("sub", Value::BaseFn(BaseFn::Binary(sub))),
|
||||
("tan", Value::BaseFn(BaseFn::Unary(tan))),
|
||||
("trim", Value::BaseFn(BaseFn::Unary(trim))),
|
||||
("triml", Value::BaseFn(BaseFn::Unary(triml))),
|
||||
("trimr", Value::BaseFn(BaseFn::Unary(trimr))),
|
||||
("type", Value::BaseFn(BaseFn::Unary(r#type))),
|
||||
("unbox", Value::BaseFn(BaseFn::Unary(unbox))),
|
||||
("upcase", Value::BaseFn(BaseFn::Unary(upcase))),
|
||||
("store!", Value::BaseFn(BaseFn::Binary("store!", store))),
|
||||
("sub", Value::BaseFn(BaseFn::Binary("sub", sub))),
|
||||
("tan", Value::BaseFn(BaseFn::Unary("tan", tan))),
|
||||
("trim", Value::BaseFn(BaseFn::Unary("trim", trim))),
|
||||
("triml", Value::BaseFn(BaseFn::Unary("triml", triml))),
|
||||
("trimr", Value::BaseFn(BaseFn::Unary("trimr", trimr))),
|
||||
("type", Value::BaseFn(BaseFn::Unary("type", r#type))),
|
||||
("unbox", Value::BaseFn(BaseFn::Unary("unbox", unbox))),
|
||||
("upcase", Value::BaseFn(BaseFn::Unary("upcase", upcase))),
|
||||
];
|
||||
Value::Dict(Box::new(HashMap::from(members)))
|
||||
}
|
||||
|
|
113
src/compiler.rs
113
src/compiler.rs
|
@ -26,7 +26,7 @@ pub enum Op {
|
|||
PushBinding,
|
||||
PushGlobal,
|
||||
Store,
|
||||
StoreAt,
|
||||
StoreN,
|
||||
Stash,
|
||||
Load,
|
||||
ResetMatch,
|
||||
|
@ -96,6 +96,8 @@ pub enum Op {
|
|||
Print,
|
||||
SetUpvalue,
|
||||
GetUpvalue,
|
||||
|
||||
Msg,
|
||||
// Inc,
|
||||
// Dec,
|
||||
// Gt,
|
||||
|
@ -140,6 +142,7 @@ impl std::fmt::Display for Op {
|
|||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
use Op::*;
|
||||
let rep = match self {
|
||||
Msg => "msg",
|
||||
Noop => "noop",
|
||||
Nothing => "nothing",
|
||||
Nil => "nil",
|
||||
|
@ -154,7 +157,7 @@ impl std::fmt::Display for Op {
|
|||
PushBinding => "push_binding",
|
||||
PushGlobal => "push_global",
|
||||
Store => "store",
|
||||
StoreAt => "store_at",
|
||||
StoreN => "store_n",
|
||||
Stash => "stash",
|
||||
Load => "load",
|
||||
Match => "match",
|
||||
|
@ -268,7 +271,8 @@ impl Chunk {
|
|||
| Duplicate | Decrement | Truncate | Noop | LoadTuple | LoadList | Eq | Add | Sub
|
||||
| Mult | Div | Unbox | BoxStore | Assert | Get | At | Not | Panic | EmptyString
|
||||
| ConcatStrings | Stringify | MatchType | Return | Match | Print | AppendList
|
||||
| ConcatList | PushList | PushDict | AppendDict | ConcatDict | Nothing | PushGlobal => {
|
||||
| ConcatList | PushList | PushDict | AppendDict | ConcatDict | Nothing | PushGlobal
|
||||
| SetUpvalue | Msg => {
|
||||
println!("{i:04}: {op}")
|
||||
}
|
||||
Constant | MatchConstant => {
|
||||
|
@ -281,9 +285,8 @@ impl Chunk {
|
|||
}
|
||||
PushBinding | MatchTuple | MatchSplattedTuple | LoadSplattedTuple | MatchList
|
||||
| MatchSplattedList | LoadSplattedList | MatchDict | MatchSplattedDict
|
||||
| DropDictEntry | LoadDictValue | PushTuple | PushBox | MatchDepth | PopN | StoreAt
|
||||
| Call | SetUpvalue | GetUpvalue | Partial | MatchString | PushStringMatches
|
||||
| TailCall => {
|
||||
| DropDictEntry | LoadDictValue | PushTuple | PushBox | MatchDepth | PopN | StoreN
|
||||
| Call | GetUpvalue | Partial | MatchString | PushStringMatches | TailCall => {
|
||||
let next = self.bytecode[*i + 1];
|
||||
println!("{i:04}: {:16} {next:03}", op.to_string());
|
||||
*i += 1;
|
||||
|
@ -364,7 +367,7 @@ pub struct Compiler<'a> {
|
|||
pub src: &'static str,
|
||||
pub name: &'static str,
|
||||
pub enclosing: Option<&'a Compiler<'a>>,
|
||||
pub upvalues: Vec<Upvalue>,
|
||||
pub upvalues: Vec<&'static str>,
|
||||
loop_info: Vec<LoopInfo>,
|
||||
tail_pos: bool,
|
||||
}
|
||||
|
@ -383,12 +386,6 @@ fn has_placeholder(args: &[Spanned<Ast>]) -> bool {
|
|||
args.iter().any(|arg| matches!(arg, (Ast::Placeholder, _)))
|
||||
}
|
||||
|
||||
fn as_two_bytes(x: usize) -> (u8, u8) {
|
||||
let low = x as u8;
|
||||
let high = (x >> 8) as u8;
|
||||
(high, low)
|
||||
}
|
||||
|
||||
impl<'a> Compiler<'a> {
|
||||
pub fn new(
|
||||
ast: &'static Spanned<Ast>,
|
||||
|
@ -535,27 +532,7 @@ impl<'a> Compiler<'a> {
|
|||
}
|
||||
|
||||
fn resolve_upvalue(&self, name: &'static str) -> Option<usize> {
|
||||
self.upvalues.iter().position(|uv| uv.name == name)
|
||||
}
|
||||
|
||||
fn get_upvalue(&self, name: &'static str) -> Upvalue {
|
||||
let local = self.bindings.iter().find(|b| b.name == name);
|
||||
match local {
|
||||
Some(binding) => {
|
||||
let upvalue = Upvalue {
|
||||
name,
|
||||
stack_pos: binding.stack_pos,
|
||||
};
|
||||
println!("found upvalue {name} in {}", self.name);
|
||||
upvalue
|
||||
}
|
||||
None => {
|
||||
println!("Getting upvalue {name}");
|
||||
let upvalue = self.enclosing.unwrap().get_upvalue(name);
|
||||
println!("upvalue: {:?}", upvalue);
|
||||
upvalue
|
||||
}
|
||||
}
|
||||
self.upvalues.iter().position(|uv| *uv == name)
|
||||
}
|
||||
|
||||
fn resolve_binding(&mut self, name: &'static str) {
|
||||
|
@ -576,40 +553,12 @@ impl<'a> Compiler<'a> {
|
|||
self.emit_op(Op::PushGlobal);
|
||||
return;
|
||||
}
|
||||
let upvalue = self.get_upvalue(name);
|
||||
self.emit_op(Op::GetUpvalue);
|
||||
self.emit_byte(self.upvalues.len());
|
||||
self.upvalues.push(upvalue);
|
||||
self.upvalues.push(name);
|
||||
self.stack_depth += 1;
|
||||
}
|
||||
|
||||
fn resolve_binding_old(&mut self, name: &'static str) {
|
||||
match self.resolve_local(name) {
|
||||
Some(position) => {
|
||||
self.emit_op(Op::PushBinding);
|
||||
self.emit_byte(position);
|
||||
self.stack_depth += 1;
|
||||
}
|
||||
None => match self.resolve_upvalue(name) {
|
||||
Some(position) => {
|
||||
println!("resolved upvalue: {name} at {position}");
|
||||
self.emit_op(Op::GetUpvalue);
|
||||
self.emit_byte(position);
|
||||
self.stack_depth += 1;
|
||||
}
|
||||
None => {
|
||||
println!("setting upvalue: {name}");
|
||||
let upvalue = self.get_upvalue(name);
|
||||
self.emit_op(Op::GetUpvalue);
|
||||
self.emit_byte(self.upvalues.len());
|
||||
self.upvalues.push(upvalue);
|
||||
dbg!(&self.upvalues);
|
||||
self.stack_depth += 1;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn pop(&mut self) {
|
||||
self.emit_op(Op::Pop);
|
||||
self.stack_depth -= 1;
|
||||
|
@ -648,6 +597,13 @@ impl<'a> Compiler<'a> {
|
|||
self.loop_info.last().unwrap().stack_root
|
||||
}
|
||||
|
||||
fn msg(&mut self, str: String) {
|
||||
let leaked = Box::leak(str.into_boxed_str());
|
||||
self.emit_constant(Value::Interned(leaked));
|
||||
self.emit_op(Op::Msg);
|
||||
self.stack_depth -= 1;
|
||||
}
|
||||
|
||||
pub fn compile(&mut self) {
|
||||
use Ast::*;
|
||||
match self.ast {
|
||||
|
@ -1377,7 +1333,7 @@ impl<'a> Compiler<'a> {
|
|||
for idx in no_match_jumps {
|
||||
compiler.patch_jump(idx, compiler.len() - idx - 3);
|
||||
}
|
||||
compiler.scope_depth -= 1;
|
||||
// compiler.scope_depth -= 1;
|
||||
|
||||
std::mem::swap(&mut compiler.upvalues, &mut upvalues);
|
||||
}
|
||||
|
@ -1442,8 +1398,9 @@ impl<'a> Compiler<'a> {
|
|||
}
|
||||
|
||||
for upvalue in upvalues {
|
||||
self.resolve_binding(upvalue);
|
||||
self.emit_op(Op::SetUpvalue);
|
||||
self.emit_byte(upvalue.stack_pos);
|
||||
self.stack_depth -= 1;
|
||||
}
|
||||
}
|
||||
FnDeclaration(name) => {
|
||||
|
@ -1483,17 +1440,21 @@ impl<'a> Compiler<'a> {
|
|||
let (Ast::Tuple(members), _) = value.as_ref() else {
|
||||
unreachable!()
|
||||
};
|
||||
for (i, member) in members.iter().enumerate() {
|
||||
for member in members {
|
||||
self.visit(member);
|
||||
self.emit_op(Op::StoreAt);
|
||||
self.emit_byte(i);
|
||||
}
|
||||
self.msg(format!(
|
||||
"entering loop with stack depth of {}",
|
||||
self.stack_depth
|
||||
));
|
||||
self.emit_op(Op::StoreN);
|
||||
self.emit_byte(members.len());
|
||||
let arity = members.len();
|
||||
let stack_depth = self.stack_depth;
|
||||
//then, save the beginning of the loop
|
||||
self.emit_op(Op::Load);
|
||||
self.enter_loop();
|
||||
self.stack_depth += arity;
|
||||
// self.stack_depth += arity;
|
||||
//next, compile each clause:
|
||||
let mut clauses = clauses.iter();
|
||||
let mut jump_idxes = vec![];
|
||||
|
@ -1550,15 +1511,21 @@ impl<'a> Compiler<'a> {
|
|||
self.leave_loop();
|
||||
}
|
||||
Recur(args) => {
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
let tail_pos = self.tail_pos;
|
||||
self.tail_pos = false;
|
||||
let mut argnum = 0;
|
||||
for arg in args {
|
||||
self.msg(format!("recur arg: {argnum}"));
|
||||
argnum += 1;
|
||||
self.visit(arg);
|
||||
self.emit_op(Op::StoreAt);
|
||||
self.emit_byte(i);
|
||||
}
|
||||
self.emit_op(Op::StoreN);
|
||||
self.emit_byte(args.len());
|
||||
self.emit_op(Op::PopN);
|
||||
self.emit_byte(self.loop_root());
|
||||
self.emit_byte(self.stack_depth - self.loop_root());
|
||||
self.emit_op(Op::Load);
|
||||
self.jump(Op::JumpBack, self.len() - self.loop_idx());
|
||||
self.tail_pos = tail_pos;
|
||||
}
|
||||
Panic(msg) => {
|
||||
self.visit(msg);
|
||||
|
|
16
src/main.rs
16
src/main.rs
|
@ -99,8 +99,8 @@ pub fn run(src: &'static str) {
|
|||
// in any event, the AST should live forever
|
||||
let parsed: &'static Spanned<Ast> = Box::leak(Box::new(parse_result.unwrap()));
|
||||
|
||||
// let prelude = prelude();
|
||||
let prelude = imbl::HashMap::new();
|
||||
let prelude = prelude();
|
||||
// let prelude = imbl::HashMap::new();
|
||||
|
||||
let mut validator = Validator::new(&parsed.0, &parsed.1, "user input", src, prelude.clone());
|
||||
validator.validate();
|
||||
|
@ -111,8 +111,6 @@ pub fn run(src: &'static str) {
|
|||
return;
|
||||
}
|
||||
|
||||
// let prelude = imbl::HashMap::new();
|
||||
|
||||
let mut compiler = Compiler::new(parsed, "test", src, None, prelude);
|
||||
// let base = base::make_base();
|
||||
// compiler.emit_constant(base);
|
||||
|
@ -145,15 +143,7 @@ pub fn run(src: &'static str) {
|
|||
pub fn main() {
|
||||
env::set_var("RUST_BACKTRACE", "1");
|
||||
let src = r#"
|
||||
let foo = {
|
||||
fn quux () -> {
|
||||
let bar = :bar
|
||||
let baz = :baz
|
||||
fn frobulate () -> (bar, baz, baz)
|
||||
}
|
||||
}
|
||||
|
||||
foo () ()
|
||||
map(inc, [1, 2, 3])
|
||||
"#;
|
||||
run(src);
|
||||
}
|
||||
|
|
12
src/value.rs
12
src/value.rs
|
@ -192,7 +192,15 @@ impl std::fmt::Display for Value {
|
|||
),
|
||||
Box(value) => write!(f, "box {{ {} }}", value.as_ref().borrow()),
|
||||
Fn(lfn) => write!(f, "fn {}", lfn.name()),
|
||||
BaseFn(_) => write!(f, "base fn"),
|
||||
BaseFn(inner) => {
|
||||
let name = match inner {
|
||||
crate::base::BaseFn::Nullary(name, _)
|
||||
| crate::base::BaseFn::Unary(name, _)
|
||||
| crate::base::BaseFn::Binary(name, _)
|
||||
| crate::base::BaseFn::Ternary(name, _) => name,
|
||||
};
|
||||
write!(f, "fn {name}/base")
|
||||
}
|
||||
Partial(partial) => write!(f, "fn {}/partial", partial.name),
|
||||
}
|
||||
}
|
||||
|
@ -235,7 +243,7 @@ impl Value {
|
|||
Box(x) => format!("box {{ {} }}", x.as_ref().borrow().show()),
|
||||
Fn(lfn) => format!("fn {}", lfn.name()),
|
||||
Partial(partial) => format!("fn {}/partial", partial.name),
|
||||
BaseFn(_) => "base fn".to_string(),
|
||||
BaseFn(_) => format!("{self}"),
|
||||
Nothing => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
|
64
src/vm.rs
64
src/vm.rs
|
@ -317,9 +317,11 @@ impl Vm {
|
|||
self.push(Value::Nothing);
|
||||
self.ip += 1;
|
||||
}
|
||||
StoreAt => {
|
||||
let i = self.chunk().bytecode[self.ip + 1] as usize;
|
||||
StoreN => {
|
||||
let n = self.chunk().bytecode[self.ip + 1] as usize;
|
||||
for i in (0..n).rev() {
|
||||
self.return_register[i] = self.pop();
|
||||
}
|
||||
self.ip += 2;
|
||||
}
|
||||
Stash => {
|
||||
|
@ -873,6 +875,10 @@ impl Vm {
|
|||
|
||||
let val = self.pop();
|
||||
|
||||
if crate::DEBUG_RUN {
|
||||
println!("=== tail call into {val}/{arity} ===");
|
||||
}
|
||||
|
||||
match val {
|
||||
Value::Fn(_) => {
|
||||
if !val.as_fn().accepts(arity) {
|
||||
|
@ -924,20 +930,18 @@ impl Vm {
|
|||
|
||||
self.ip = 0;
|
||||
|
||||
if crate::DEBUG_RUN {
|
||||
println!("== tail call into {} ==", self.frame.function.show());
|
||||
}
|
||||
if crate::DEBUG_RUN {}
|
||||
}
|
||||
Value::BaseFn(base_fn) => {
|
||||
let value = match (arity, base_fn) {
|
||||
(0, BaseFn::Nullary(f)) => f(),
|
||||
(1, BaseFn::Unary(f)) => f(&self.pop()),
|
||||
(2, BaseFn::Binary(f)) => {
|
||||
(0, BaseFn::Nullary(_, f)) => f(),
|
||||
(1, BaseFn::Unary(_, f)) => f(&self.pop()),
|
||||
(2, BaseFn::Binary(_, f)) => {
|
||||
let y = &self.pop();
|
||||
let x = &self.pop();
|
||||
f(x, y)
|
||||
}
|
||||
(3, BaseFn::Ternary(f)) => {
|
||||
(3, BaseFn::Ternary(_, f)) => {
|
||||
let z = &self.pop();
|
||||
let y = &self.pop();
|
||||
let x = &self.pop();
|
||||
|
@ -977,10 +981,6 @@ impl Vm {
|
|||
|
||||
self.call_stack.push(frame);
|
||||
self.ip = 0;
|
||||
|
||||
if crate::DEBUG_RUN {
|
||||
println!("== calling into {} ==", self.frame.function.show());
|
||||
}
|
||||
}
|
||||
_ => return self.panic_with(format!("{} is not a function", val.show())),
|
||||
}
|
||||
|
@ -991,6 +991,10 @@ impl Vm {
|
|||
|
||||
let val = self.pop();
|
||||
|
||||
if crate::DEBUG_RUN {
|
||||
println!("=== calling into {val}/{arity} ===");
|
||||
}
|
||||
|
||||
match val {
|
||||
Value::Fn(_) => {
|
||||
if !val.as_fn().accepts(arity) {
|
||||
|
@ -1024,21 +1028,17 @@ impl Vm {
|
|||
|
||||
self.call_stack.push(frame);
|
||||
self.ip = 0;
|
||||
|
||||
if crate::DEBUG_RUN {
|
||||
println!("== calling into {} ==", self.frame.function.show());
|
||||
}
|
||||
}
|
||||
Value::BaseFn(base_fn) => {
|
||||
let value = match (arity, base_fn) {
|
||||
(0, BaseFn::Nullary(f)) => f(),
|
||||
(1, BaseFn::Unary(f)) => f(&self.pop()),
|
||||
(2, BaseFn::Binary(f)) => {
|
||||
(0, BaseFn::Nullary(_, f)) => f(),
|
||||
(1, BaseFn::Unary(_, f)) => f(&self.pop()),
|
||||
(2, BaseFn::Binary(_, f)) => {
|
||||
let y = &self.pop();
|
||||
let x = &self.pop();
|
||||
f(x, y)
|
||||
}
|
||||
(3, BaseFn::Ternary(f)) => {
|
||||
(3, BaseFn::Ternary(_, f)) => {
|
||||
let z = &self.pop();
|
||||
let y = &self.pop();
|
||||
let x = &self.pop();
|
||||
|
@ -1071,10 +1071,6 @@ impl Vm {
|
|||
|
||||
self.call_stack.push(frame);
|
||||
self.ip = 0;
|
||||
|
||||
if crate::DEBUG_RUN {
|
||||
println!("== calling into {} ==", self.frame.function.show());
|
||||
}
|
||||
}
|
||||
_ => return self.panic_with(format!("{} is not a function", val.show())),
|
||||
}
|
||||
|
@ -1095,13 +1091,12 @@ impl Vm {
|
|||
self.ip += 1;
|
||||
}
|
||||
SetUpvalue => {
|
||||
let idx = self.chunk().bytecode[self.ip + 1];
|
||||
self.ip += 2;
|
||||
let closed_idx = idx as usize + self.frame.stack_base;
|
||||
let closed_over = self.stack[closed_idx].clone();
|
||||
if let Value::Fn(lfn) = self.peek() {
|
||||
lfn.close(closed_over);
|
||||
}
|
||||
let value = self.pop();
|
||||
let Value::Fn(lfn) = self.peek() else {
|
||||
panic!("expected function closing over value, got {}", self.peek());
|
||||
};
|
||||
lfn.close(value);
|
||||
self.ip += 1;
|
||||
}
|
||||
GetUpvalue => {
|
||||
let idx = self.chunk().bytecode[self.ip + 1];
|
||||
|
@ -1112,6 +1107,11 @@ impl Vm {
|
|||
unreachable!();
|
||||
}
|
||||
}
|
||||
Msg => {
|
||||
let msg = self.pop();
|
||||
println!("{msg}");
|
||||
self.ip += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user