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
|
& type
|
||||||
& coll?
|
& coll?
|
||||||
|
@ -233,7 +239,8 @@ fn map {
|
||||||
& not
|
& not
|
||||||
& tuple?
|
& tuple?
|
||||||
& fn?
|
& fn?
|
||||||
& rest
|
first
|
||||||
|
rest
|
||||||
inc
|
inc
|
||||||
& dec
|
& dec
|
||||||
& count
|
& count
|
||||||
|
@ -242,7 +249,8 @@ fn map {
|
||||||
& list?
|
& list?
|
||||||
& list
|
& list
|
||||||
& first
|
& first
|
||||||
& fold
|
fold
|
||||||
& append
|
append
|
||||||
map
|
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 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.
|
I believe I need to take the strategy he uses with closures being different from functions, etc.
|
||||||
So: rework the closures strategy here.
|
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)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum BaseFn {
|
pub enum BaseFn {
|
||||||
Nullary(fn() -> Value),
|
Nullary(&'static str, fn() -> Value),
|
||||||
Unary(fn(&Value) -> Value),
|
Unary(&'static str, fn(&Value) -> Value),
|
||||||
Binary(fn(&Value, &Value) -> Value),
|
Binary(&'static str, fn(&Value, &Value) -> Value),
|
||||||
Ternary(fn(&Value, &Value, &Value) -> Value),
|
Ternary(&'static str, fn(&Value, &Value, &Value) -> Value),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eq(x: &Value, y: &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 {
|
pub fn make_base() -> Value {
|
||||||
let members = vec![
|
let members = vec![
|
||||||
("add", Value::BaseFn(BaseFn::Binary(add))),
|
("add", Value::BaseFn(BaseFn::Binary("add", add))),
|
||||||
("append", Value::BaseFn(BaseFn::Binary(append))),
|
("append", Value::BaseFn(BaseFn::Binary("append", append))),
|
||||||
("assoc", Value::BaseFn(BaseFn::Ternary(assoc))),
|
("assoc", Value::BaseFn(BaseFn::Ternary("assoc", assoc))),
|
||||||
("at", Value::BaseFn(BaseFn::Binary(at))),
|
("at", Value::BaseFn(BaseFn::Binary("at", at))),
|
||||||
("atan_2", Value::BaseFn(BaseFn::Binary(atan_2))),
|
("atan_2", Value::BaseFn(BaseFn::Binary("atan_2", atan_2))),
|
||||||
("bool", Value::BaseFn(BaseFn::Unary(r#bool))),
|
("bool", Value::BaseFn(BaseFn::Unary("bool", r#bool))),
|
||||||
("ceil", Value::BaseFn(BaseFn::Unary(ceil))),
|
("ceil", Value::BaseFn(BaseFn::Unary("ceil", ceil))),
|
||||||
("chars", Value::BaseFn(BaseFn::Unary(chars))),
|
("chars", Value::BaseFn(BaseFn::Unary("chars", chars))),
|
||||||
("concat", Value::BaseFn(BaseFn::Binary(concat))),
|
("concat", Value::BaseFn(BaseFn::Binary("concat", concat))),
|
||||||
("cos", Value::BaseFn(BaseFn::Unary(cos))),
|
("cos", Value::BaseFn(BaseFn::Unary("cos", cos))),
|
||||||
("count", Value::BaseFn(BaseFn::Unary(count))),
|
("count", Value::BaseFn(BaseFn::Unary("count", count))),
|
||||||
("dec", Value::BaseFn(BaseFn::Unary(dec))),
|
("dec", Value::BaseFn(BaseFn::Unary("dec", dec))),
|
||||||
("dissoc", Value::BaseFn(BaseFn::Binary(dissoc))),
|
("dissoc", Value::BaseFn(BaseFn::Binary("dissoc", dissoc))),
|
||||||
("div", Value::BaseFn(BaseFn::Binary(div))),
|
("div", Value::BaseFn(BaseFn::Binary("div", div))),
|
||||||
("doc!", Value::BaseFn(BaseFn::Unary(doc))),
|
("doc!", Value::BaseFn(BaseFn::Unary("doc!", doc))),
|
||||||
("downcase", Value::BaseFn(BaseFn::Unary(downcase))),
|
(
|
||||||
("eq?", Value::BaseFn(BaseFn::Binary(eq))),
|
"downcase",
|
||||||
("first", Value::BaseFn(BaseFn::Unary(first))),
|
Value::BaseFn(BaseFn::Unary("downcase", downcase)),
|
||||||
("floor", Value::BaseFn(BaseFn::Unary(floor))),
|
),
|
||||||
("get", Value::BaseFn(BaseFn::Binary(get))),
|
("eq?", Value::BaseFn(BaseFn::Binary("eq?", eq))),
|
||||||
("gt?", Value::BaseFn(BaseFn::Binary(gt))),
|
("first", Value::BaseFn(BaseFn::Unary("first", first))),
|
||||||
("gte?", Value::BaseFn(BaseFn::Binary(gte))),
|
("floor", Value::BaseFn(BaseFn::Unary("floor", floor))),
|
||||||
("inc", Value::BaseFn(BaseFn::Unary(inc))),
|
("get", Value::BaseFn(BaseFn::Binary("get", get))),
|
||||||
("last", Value::BaseFn(BaseFn::Unary(last))),
|
("gt?", Value::BaseFn(BaseFn::Binary("gt?", gt))),
|
||||||
("list", Value::BaseFn(BaseFn::Unary(list))),
|
("gte?", Value::BaseFn(BaseFn::Binary("gte?", gte))),
|
||||||
("lt?", Value::BaseFn(BaseFn::Binary(lt))),
|
("inc", Value::BaseFn(BaseFn::Unary("inc", inc))),
|
||||||
("lte?", Value::BaseFn(BaseFn::Binary(lte))),
|
("last", Value::BaseFn(BaseFn::Unary("last", last))),
|
||||||
("mod", Value::BaseFn(BaseFn::Binary(r#mod))),
|
("list", Value::BaseFn(BaseFn::Unary("list", list))),
|
||||||
("mult", Value::BaseFn(BaseFn::Binary(mult))),
|
("lt?", Value::BaseFn(BaseFn::Binary("lt?", lt))),
|
||||||
("number", Value::BaseFn(BaseFn::Unary(number))),
|
("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)),
|
("pi", Value::Number(std::f64::consts::PI)),
|
||||||
("print!", Value::BaseFn(BaseFn::Unary(print))),
|
("print!", Value::BaseFn(BaseFn::Unary("print!", print))),
|
||||||
("random", Value::BaseFn(BaseFn::Nullary(random))),
|
("random", Value::BaseFn(BaseFn::Nullary("random", random))),
|
||||||
("range", Value::BaseFn(BaseFn::Binary(range))),
|
("range", Value::BaseFn(BaseFn::Binary("range", range))),
|
||||||
("rest", Value::BaseFn(BaseFn::Unary(rest))),
|
("rest", Value::BaseFn(BaseFn::Unary("rest", rest))),
|
||||||
("round", Value::BaseFn(BaseFn::Unary(round))),
|
("round", Value::BaseFn(BaseFn::Unary("round", round))),
|
||||||
("show", Value::BaseFn(BaseFn::Unary(show))),
|
("show", Value::BaseFn(BaseFn::Unary("show", show))),
|
||||||
("sin", Value::BaseFn(BaseFn::Unary(sin))),
|
("sin", Value::BaseFn(BaseFn::Unary("sin", sin))),
|
||||||
("slice", Value::BaseFn(BaseFn::Ternary(slice))),
|
("slice", Value::BaseFn(BaseFn::Ternary("slice", slice))),
|
||||||
("split", Value::BaseFn(BaseFn::Binary(split))),
|
("split", Value::BaseFn(BaseFn::Binary("split", split))),
|
||||||
("sqrt", Value::BaseFn(BaseFn::Unary(sqrt))),
|
("sqrt", Value::BaseFn(BaseFn::Unary("sqrt", sqrt))),
|
||||||
("sqrt_2", Value::Number(std::f64::consts::SQRT_2)),
|
("sqrt_2", Value::Number(std::f64::consts::SQRT_2)),
|
||||||
("store!", Value::BaseFn(BaseFn::Binary(store))),
|
("store!", Value::BaseFn(BaseFn::Binary("store!", store))),
|
||||||
("sub", Value::BaseFn(BaseFn::Binary(sub))),
|
("sub", Value::BaseFn(BaseFn::Binary("sub", sub))),
|
||||||
("tan", Value::BaseFn(BaseFn::Unary(tan))),
|
("tan", Value::BaseFn(BaseFn::Unary("tan", tan))),
|
||||||
("trim", Value::BaseFn(BaseFn::Unary(trim))),
|
("trim", Value::BaseFn(BaseFn::Unary("trim", trim))),
|
||||||
("triml", Value::BaseFn(BaseFn::Unary(triml))),
|
("triml", Value::BaseFn(BaseFn::Unary("triml", triml))),
|
||||||
("trimr", Value::BaseFn(BaseFn::Unary(trimr))),
|
("trimr", Value::BaseFn(BaseFn::Unary("trimr", trimr))),
|
||||||
("type", Value::BaseFn(BaseFn::Unary(r#type))),
|
("type", Value::BaseFn(BaseFn::Unary("type", r#type))),
|
||||||
("unbox", Value::BaseFn(BaseFn::Unary(unbox))),
|
("unbox", Value::BaseFn(BaseFn::Unary("unbox", unbox))),
|
||||||
("upcase", Value::BaseFn(BaseFn::Unary(upcase))),
|
("upcase", Value::BaseFn(BaseFn::Unary("upcase", upcase))),
|
||||||
];
|
];
|
||||||
Value::Dict(Box::new(HashMap::from(members)))
|
Value::Dict(Box::new(HashMap::from(members)))
|
||||||
}
|
}
|
||||||
|
|
113
src/compiler.rs
113
src/compiler.rs
|
@ -26,7 +26,7 @@ pub enum Op {
|
||||||
PushBinding,
|
PushBinding,
|
||||||
PushGlobal,
|
PushGlobal,
|
||||||
Store,
|
Store,
|
||||||
StoreAt,
|
StoreN,
|
||||||
Stash,
|
Stash,
|
||||||
Load,
|
Load,
|
||||||
ResetMatch,
|
ResetMatch,
|
||||||
|
@ -96,6 +96,8 @@ pub enum Op {
|
||||||
Print,
|
Print,
|
||||||
SetUpvalue,
|
SetUpvalue,
|
||||||
GetUpvalue,
|
GetUpvalue,
|
||||||
|
|
||||||
|
Msg,
|
||||||
// Inc,
|
// Inc,
|
||||||
// Dec,
|
// Dec,
|
||||||
// Gt,
|
// Gt,
|
||||||
|
@ -140,6 +142,7 @@ impl std::fmt::Display for Op {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
use Op::*;
|
use Op::*;
|
||||||
let rep = match self {
|
let rep = match self {
|
||||||
|
Msg => "msg",
|
||||||
Noop => "noop",
|
Noop => "noop",
|
||||||
Nothing => "nothing",
|
Nothing => "nothing",
|
||||||
Nil => "nil",
|
Nil => "nil",
|
||||||
|
@ -154,7 +157,7 @@ impl std::fmt::Display for Op {
|
||||||
PushBinding => "push_binding",
|
PushBinding => "push_binding",
|
||||||
PushGlobal => "push_global",
|
PushGlobal => "push_global",
|
||||||
Store => "store",
|
Store => "store",
|
||||||
StoreAt => "store_at",
|
StoreN => "store_n",
|
||||||
Stash => "stash",
|
Stash => "stash",
|
||||||
Load => "load",
|
Load => "load",
|
||||||
Match => "match",
|
Match => "match",
|
||||||
|
@ -268,7 +271,8 @@ impl Chunk {
|
||||||
| Duplicate | Decrement | Truncate | Noop | LoadTuple | LoadList | Eq | Add | Sub
|
| Duplicate | Decrement | Truncate | Noop | LoadTuple | LoadList | Eq | Add | Sub
|
||||||
| Mult | Div | Unbox | BoxStore | Assert | Get | At | Not | Panic | EmptyString
|
| Mult | Div | Unbox | BoxStore | Assert | Get | At | Not | Panic | EmptyString
|
||||||
| ConcatStrings | Stringify | MatchType | Return | Match | Print | AppendList
|
| 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}")
|
println!("{i:04}: {op}")
|
||||||
}
|
}
|
||||||
Constant | MatchConstant => {
|
Constant | MatchConstant => {
|
||||||
|
@ -281,9 +285,8 @@ impl Chunk {
|
||||||
}
|
}
|
||||||
PushBinding | MatchTuple | MatchSplattedTuple | LoadSplattedTuple | MatchList
|
PushBinding | MatchTuple | MatchSplattedTuple | LoadSplattedTuple | MatchList
|
||||||
| MatchSplattedList | LoadSplattedList | MatchDict | MatchSplattedDict
|
| MatchSplattedList | LoadSplattedList | MatchDict | MatchSplattedDict
|
||||||
| DropDictEntry | LoadDictValue | PushTuple | PushBox | MatchDepth | PopN | StoreAt
|
| DropDictEntry | LoadDictValue | PushTuple | PushBox | MatchDepth | PopN | StoreN
|
||||||
| Call | SetUpvalue | GetUpvalue | Partial | MatchString | PushStringMatches
|
| Call | GetUpvalue | Partial | MatchString | PushStringMatches | TailCall => {
|
||||||
| TailCall => {
|
|
||||||
let next = self.bytecode[*i + 1];
|
let next = self.bytecode[*i + 1];
|
||||||
println!("{i:04}: {:16} {next:03}", op.to_string());
|
println!("{i:04}: {:16} {next:03}", op.to_string());
|
||||||
*i += 1;
|
*i += 1;
|
||||||
|
@ -364,7 +367,7 @@ pub struct Compiler<'a> {
|
||||||
pub src: &'static str,
|
pub src: &'static str,
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
pub enclosing: Option<&'a Compiler<'a>>,
|
pub enclosing: Option<&'a Compiler<'a>>,
|
||||||
pub upvalues: Vec<Upvalue>,
|
pub upvalues: Vec<&'static str>,
|
||||||
loop_info: Vec<LoopInfo>,
|
loop_info: Vec<LoopInfo>,
|
||||||
tail_pos: bool,
|
tail_pos: bool,
|
||||||
}
|
}
|
||||||
|
@ -383,12 +386,6 @@ fn has_placeholder(args: &[Spanned<Ast>]) -> bool {
|
||||||
args.iter().any(|arg| matches!(arg, (Ast::Placeholder, _)))
|
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> {
|
impl<'a> Compiler<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
ast: &'static Spanned<Ast>,
|
ast: &'static Spanned<Ast>,
|
||||||
|
@ -535,27 +532,7 @@ impl<'a> Compiler<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_upvalue(&self, name: &'static str) -> Option<usize> {
|
fn resolve_upvalue(&self, name: &'static str) -> Option<usize> {
|
||||||
self.upvalues.iter().position(|uv| uv.name == name)
|
self.upvalues.iter().position(|uv| *uv == 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_binding(&mut self, name: &'static str) {
|
fn resolve_binding(&mut self, name: &'static str) {
|
||||||
|
@ -576,40 +553,12 @@ impl<'a> Compiler<'a> {
|
||||||
self.emit_op(Op::PushGlobal);
|
self.emit_op(Op::PushGlobal);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let upvalue = self.get_upvalue(name);
|
|
||||||
self.emit_op(Op::GetUpvalue);
|
self.emit_op(Op::GetUpvalue);
|
||||||
self.emit_byte(self.upvalues.len());
|
self.emit_byte(self.upvalues.len());
|
||||||
self.upvalues.push(upvalue);
|
self.upvalues.push(name);
|
||||||
self.stack_depth += 1;
|
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) {
|
fn pop(&mut self) {
|
||||||
self.emit_op(Op::Pop);
|
self.emit_op(Op::Pop);
|
||||||
self.stack_depth -= 1;
|
self.stack_depth -= 1;
|
||||||
|
@ -648,6 +597,13 @@ impl<'a> Compiler<'a> {
|
||||||
self.loop_info.last().unwrap().stack_root
|
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) {
|
pub fn compile(&mut self) {
|
||||||
use Ast::*;
|
use Ast::*;
|
||||||
match self.ast {
|
match self.ast {
|
||||||
|
@ -1377,7 +1333,7 @@ impl<'a> Compiler<'a> {
|
||||||
for idx in no_match_jumps {
|
for idx in no_match_jumps {
|
||||||
compiler.patch_jump(idx, compiler.len() - idx - 3);
|
compiler.patch_jump(idx, compiler.len() - idx - 3);
|
||||||
}
|
}
|
||||||
compiler.scope_depth -= 1;
|
// compiler.scope_depth -= 1;
|
||||||
|
|
||||||
std::mem::swap(&mut compiler.upvalues, &mut upvalues);
|
std::mem::swap(&mut compiler.upvalues, &mut upvalues);
|
||||||
}
|
}
|
||||||
|
@ -1442,8 +1398,9 @@ impl<'a> Compiler<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
for upvalue in upvalues {
|
for upvalue in upvalues {
|
||||||
|
self.resolve_binding(upvalue);
|
||||||
self.emit_op(Op::SetUpvalue);
|
self.emit_op(Op::SetUpvalue);
|
||||||
self.emit_byte(upvalue.stack_pos);
|
self.stack_depth -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FnDeclaration(name) => {
|
FnDeclaration(name) => {
|
||||||
|
@ -1483,17 +1440,21 @@ impl<'a> Compiler<'a> {
|
||||||
let (Ast::Tuple(members), _) = value.as_ref() else {
|
let (Ast::Tuple(members), _) = value.as_ref() else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
for (i, member) in members.iter().enumerate() {
|
for member in members {
|
||||||
self.visit(member);
|
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 arity = members.len();
|
||||||
let stack_depth = self.stack_depth;
|
let stack_depth = self.stack_depth;
|
||||||
//then, save the beginning of the loop
|
//then, save the beginning of the loop
|
||||||
self.emit_op(Op::Load);
|
self.emit_op(Op::Load);
|
||||||
self.enter_loop();
|
self.enter_loop();
|
||||||
self.stack_depth += arity;
|
// self.stack_depth += arity;
|
||||||
//next, compile each clause:
|
//next, compile each clause:
|
||||||
let mut clauses = clauses.iter();
|
let mut clauses = clauses.iter();
|
||||||
let mut jump_idxes = vec![];
|
let mut jump_idxes = vec![];
|
||||||
|
@ -1550,15 +1511,21 @@ impl<'a> Compiler<'a> {
|
||||||
self.leave_loop();
|
self.leave_loop();
|
||||||
}
|
}
|
||||||
Recur(args) => {
|
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.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_op(Op::PopN);
|
||||||
self.emit_byte(self.loop_root());
|
self.emit_byte(self.stack_depth - self.loop_root());
|
||||||
self.emit_op(Op::Load);
|
self.emit_op(Op::Load);
|
||||||
self.jump(Op::JumpBack, self.len() - self.loop_idx());
|
self.jump(Op::JumpBack, self.len() - self.loop_idx());
|
||||||
|
self.tail_pos = tail_pos;
|
||||||
}
|
}
|
||||||
Panic(msg) => {
|
Panic(msg) => {
|
||||||
self.visit(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
|
// in any event, the AST should live forever
|
||||||
let parsed: &'static Spanned<Ast> = Box::leak(Box::new(parse_result.unwrap()));
|
let parsed: &'static Spanned<Ast> = Box::leak(Box::new(parse_result.unwrap()));
|
||||||
|
|
||||||
// let prelude = prelude();
|
let prelude = prelude();
|
||||||
let prelude = imbl::HashMap::new();
|
// let prelude = imbl::HashMap::new();
|
||||||
|
|
||||||
let mut validator = Validator::new(&parsed.0, &parsed.1, "user input", src, prelude.clone());
|
let mut validator = Validator::new(&parsed.0, &parsed.1, "user input", src, prelude.clone());
|
||||||
validator.validate();
|
validator.validate();
|
||||||
|
@ -111,8 +111,6 @@ pub fn run(src: &'static str) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// let prelude = imbl::HashMap::new();
|
|
||||||
|
|
||||||
let mut compiler = Compiler::new(parsed, "test", src, None, prelude);
|
let mut compiler = Compiler::new(parsed, "test", src, None, prelude);
|
||||||
// let base = base::make_base();
|
// let base = base::make_base();
|
||||||
// compiler.emit_constant(base);
|
// compiler.emit_constant(base);
|
||||||
|
@ -145,15 +143,7 @@ pub fn run(src: &'static str) {
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
env::set_var("RUST_BACKTRACE", "1");
|
env::set_var("RUST_BACKTRACE", "1");
|
||||||
let src = r#"
|
let src = r#"
|
||||||
let foo = {
|
map(inc, [1, 2, 3])
|
||||||
fn quux () -> {
|
|
||||||
let bar = :bar
|
|
||||||
let baz = :baz
|
|
||||||
fn frobulate () -> (bar, baz, baz)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foo () ()
|
|
||||||
"#;
|
"#;
|
||||||
run(src);
|
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()),
|
Box(value) => write!(f, "box {{ {} }}", value.as_ref().borrow()),
|
||||||
Fn(lfn) => write!(f, "fn {}", lfn.name()),
|
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),
|
Partial(partial) => write!(f, "fn {}/partial", partial.name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,7 +243,7 @@ impl Value {
|
||||||
Box(x) => format!("box {{ {} }}", x.as_ref().borrow().show()),
|
Box(x) => format!("box {{ {} }}", x.as_ref().borrow().show()),
|
||||||
Fn(lfn) => format!("fn {}", lfn.name()),
|
Fn(lfn) => format!("fn {}", lfn.name()),
|
||||||
Partial(partial) => format!("fn {}/partial", partial.name),
|
Partial(partial) => format!("fn {}/partial", partial.name),
|
||||||
BaseFn(_) => "base fn".to_string(),
|
BaseFn(_) => format!("{self}"),
|
||||||
Nothing => unreachable!(),
|
Nothing => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
66
src/vm.rs
66
src/vm.rs
|
@ -317,9 +317,11 @@ impl Vm {
|
||||||
self.push(Value::Nothing);
|
self.push(Value::Nothing);
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
}
|
}
|
||||||
StoreAt => {
|
StoreN => {
|
||||||
let i = self.chunk().bytecode[self.ip + 1] as usize;
|
let n = self.chunk().bytecode[self.ip + 1] as usize;
|
||||||
self.return_register[i] = self.pop();
|
for i in (0..n).rev() {
|
||||||
|
self.return_register[i] = self.pop();
|
||||||
|
}
|
||||||
self.ip += 2;
|
self.ip += 2;
|
||||||
}
|
}
|
||||||
Stash => {
|
Stash => {
|
||||||
|
@ -873,6 +875,10 @@ impl Vm {
|
||||||
|
|
||||||
let val = self.pop();
|
let val = self.pop();
|
||||||
|
|
||||||
|
if crate::DEBUG_RUN {
|
||||||
|
println!("=== tail call into {val}/{arity} ===");
|
||||||
|
}
|
||||||
|
|
||||||
match val {
|
match val {
|
||||||
Value::Fn(_) => {
|
Value::Fn(_) => {
|
||||||
if !val.as_fn().accepts(arity) {
|
if !val.as_fn().accepts(arity) {
|
||||||
|
@ -924,20 +930,18 @@ impl Vm {
|
||||||
|
|
||||||
self.ip = 0;
|
self.ip = 0;
|
||||||
|
|
||||||
if crate::DEBUG_RUN {
|
if crate::DEBUG_RUN {}
|
||||||
println!("== tail call into {} ==", self.frame.function.show());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Value::BaseFn(base_fn) => {
|
Value::BaseFn(base_fn) => {
|
||||||
let value = match (arity, base_fn) {
|
let value = match (arity, base_fn) {
|
||||||
(0, BaseFn::Nullary(f)) => f(),
|
(0, BaseFn::Nullary(_, f)) => f(),
|
||||||
(1, BaseFn::Unary(f)) => f(&self.pop()),
|
(1, BaseFn::Unary(_, f)) => f(&self.pop()),
|
||||||
(2, BaseFn::Binary(f)) => {
|
(2, BaseFn::Binary(_, f)) => {
|
||||||
let y = &self.pop();
|
let y = &self.pop();
|
||||||
let x = &self.pop();
|
let x = &self.pop();
|
||||||
f(x, y)
|
f(x, y)
|
||||||
}
|
}
|
||||||
(3, BaseFn::Ternary(f)) => {
|
(3, BaseFn::Ternary(_, f)) => {
|
||||||
let z = &self.pop();
|
let z = &self.pop();
|
||||||
let y = &self.pop();
|
let y = &self.pop();
|
||||||
let x = &self.pop();
|
let x = &self.pop();
|
||||||
|
@ -977,10 +981,6 @@ impl Vm {
|
||||||
|
|
||||||
self.call_stack.push(frame);
|
self.call_stack.push(frame);
|
||||||
self.ip = 0;
|
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())),
|
_ => return self.panic_with(format!("{} is not a function", val.show())),
|
||||||
}
|
}
|
||||||
|
@ -991,6 +991,10 @@ impl Vm {
|
||||||
|
|
||||||
let val = self.pop();
|
let val = self.pop();
|
||||||
|
|
||||||
|
if crate::DEBUG_RUN {
|
||||||
|
println!("=== calling into {val}/{arity} ===");
|
||||||
|
}
|
||||||
|
|
||||||
match val {
|
match val {
|
||||||
Value::Fn(_) => {
|
Value::Fn(_) => {
|
||||||
if !val.as_fn().accepts(arity) {
|
if !val.as_fn().accepts(arity) {
|
||||||
|
@ -1024,21 +1028,17 @@ impl Vm {
|
||||||
|
|
||||||
self.call_stack.push(frame);
|
self.call_stack.push(frame);
|
||||||
self.ip = 0;
|
self.ip = 0;
|
||||||
|
|
||||||
if crate::DEBUG_RUN {
|
|
||||||
println!("== calling into {} ==", self.frame.function.show());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Value::BaseFn(base_fn) => {
|
Value::BaseFn(base_fn) => {
|
||||||
let value = match (arity, base_fn) {
|
let value = match (arity, base_fn) {
|
||||||
(0, BaseFn::Nullary(f)) => f(),
|
(0, BaseFn::Nullary(_, f)) => f(),
|
||||||
(1, BaseFn::Unary(f)) => f(&self.pop()),
|
(1, BaseFn::Unary(_, f)) => f(&self.pop()),
|
||||||
(2, BaseFn::Binary(f)) => {
|
(2, BaseFn::Binary(_, f)) => {
|
||||||
let y = &self.pop();
|
let y = &self.pop();
|
||||||
let x = &self.pop();
|
let x = &self.pop();
|
||||||
f(x, y)
|
f(x, y)
|
||||||
}
|
}
|
||||||
(3, BaseFn::Ternary(f)) => {
|
(3, BaseFn::Ternary(_, f)) => {
|
||||||
let z = &self.pop();
|
let z = &self.pop();
|
||||||
let y = &self.pop();
|
let y = &self.pop();
|
||||||
let x = &self.pop();
|
let x = &self.pop();
|
||||||
|
@ -1071,10 +1071,6 @@ impl Vm {
|
||||||
|
|
||||||
self.call_stack.push(frame);
|
self.call_stack.push(frame);
|
||||||
self.ip = 0;
|
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())),
|
_ => return self.panic_with(format!("{} is not a function", val.show())),
|
||||||
}
|
}
|
||||||
|
@ -1095,13 +1091,12 @@ impl Vm {
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
}
|
}
|
||||||
SetUpvalue => {
|
SetUpvalue => {
|
||||||
let idx = self.chunk().bytecode[self.ip + 1];
|
let value = self.pop();
|
||||||
self.ip += 2;
|
let Value::Fn(lfn) = self.peek() else {
|
||||||
let closed_idx = idx as usize + self.frame.stack_base;
|
panic!("expected function closing over value, got {}", self.peek());
|
||||||
let closed_over = self.stack[closed_idx].clone();
|
};
|
||||||
if let Value::Fn(lfn) = self.peek() {
|
lfn.close(value);
|
||||||
lfn.close(closed_over);
|
self.ip += 1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
GetUpvalue => {
|
GetUpvalue => {
|
||||||
let idx = self.chunk().bytecode[self.ip + 1];
|
let idx = self.chunk().bytecode[self.ip + 1];
|
||||||
|
@ -1112,6 +1107,11 @@ impl Vm {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Msg => {
|
||||||
|
let msg = self.pop();
|
||||||
|
println!("{msg}");
|
||||||
|
self.ip += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user