Compare commits

..

No commits in common. "25a0c62dcf4fc80fb1494cabfc9c9b9b8604ed13" and "ce11f1cd0fbc09640cea2ab138f780ab36c97d47" have entirely different histories.

7 changed files with 169 additions and 165 deletions

View File

@ -217,12 +217,6 @@ fn map {
& }
}
fn add {
() -> 0
(x) -> x
(x, y) -> base :add (x, y)
}
#{
& type
& coll?
@ -239,8 +233,7 @@ fn add {
& not
& tuple?
& fn?
first
rest
& rest
inc
& dec
& count
@ -249,8 +242,7 @@ fn add {
& list?
& list
& first
fold
append
& fold
& append
map
add
}

View File

@ -422,15 +422,3 @@ 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.

View File

@ -5,10 +5,10 @@ use std::rc::Rc;
#[derive(Clone, Debug)]
pub enum BaseFn {
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),
Nullary(fn() -> Value),
Unary(fn(&Value) -> Value),
Binary(fn(&Value, &Value) -> Value),
Ternary(fn(&Value, &Value, &Value) -> Value),
}
pub fn eq(x: &Value, y: &Value) -> Value {
@ -585,60 +585,57 @@ pub fn r#mod(x: &Value, y: &Value) -> Value {
pub fn make_base() -> Value {
let members = vec![
("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))),
("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))),
("pi", Value::Number(std::f64::consts::PI)),
("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))),
("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))),
("sqrt_2", Value::Number(std::f64::consts::SQRT_2)),
("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))),
("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))),
];
Value::Dict(Box::new(HashMap::from(members)))
}

View File

@ -26,7 +26,7 @@ pub enum Op {
PushBinding,
PushGlobal,
Store,
StoreN,
StoreAt,
Stash,
Load,
ResetMatch,
@ -96,8 +96,6 @@ pub enum Op {
Print,
SetUpvalue,
GetUpvalue,
Msg,
// Inc,
// Dec,
// Gt,
@ -142,7 +140,6 @@ 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",
@ -157,7 +154,7 @@ impl std::fmt::Display for Op {
PushBinding => "push_binding",
PushGlobal => "push_global",
Store => "store",
StoreN => "store_n",
StoreAt => "store_at",
Stash => "stash",
Load => "load",
Match => "match",
@ -271,8 +268,7 @@ 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
| SetUpvalue | Msg => {
| ConcatList | PushList | PushDict | AppendDict | ConcatDict | Nothing | PushGlobal => {
println!("{i:04}: {op}")
}
Constant | MatchConstant => {
@ -285,8 +281,9 @@ impl Chunk {
}
PushBinding | MatchTuple | MatchSplattedTuple | LoadSplattedTuple | MatchList
| MatchSplattedList | LoadSplattedList | MatchDict | MatchSplattedDict
| DropDictEntry | LoadDictValue | PushTuple | PushBox | MatchDepth | PopN | StoreN
| Call | GetUpvalue | Partial | MatchString | PushStringMatches | TailCall => {
| DropDictEntry | LoadDictValue | PushTuple | PushBox | MatchDepth | PopN | StoreAt
| Call | SetUpvalue | GetUpvalue | Partial | MatchString | PushStringMatches
| TailCall => {
let next = self.bytecode[*i + 1];
println!("{i:04}: {:16} {next:03}", op.to_string());
*i += 1;
@ -367,7 +364,7 @@ pub struct Compiler<'a> {
pub src: &'static str,
pub name: &'static str,
pub enclosing: Option<&'a Compiler<'a>>,
pub upvalues: Vec<&'static str>,
pub upvalues: Vec<Upvalue>,
loop_info: Vec<LoopInfo>,
tail_pos: bool,
}
@ -386,6 +383,12 @@ 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>,
@ -532,7 +535,21 @@ impl<'a> Compiler<'a> {
}
fn resolve_upvalue(&self, name: &'static str) -> Option<usize> {
self.upvalues.iter().position(|uv| *uv == name)
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) => Upvalue {
name,
stack_pos: binding.stack_pos,
},
None => {
println!("Getting upvalue {name}");
self.enclosing.unwrap().get_upvalue(name)
}
}
}
fn resolve_binding(&mut self, name: &'static str) {
@ -553,12 +570,40 @@ 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(name);
self.upvalues.push(upvalue);
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;
@ -597,13 +642,6 @@ 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 {
@ -1271,7 +1309,7 @@ impl<'a> Compiler<'a> {
None => {
let mut compiler = Compiler::new(
clause,
name,
self.name,
self.src,
Some(self),
self.chunk.env.clone(),
@ -1333,7 +1371,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);
}
@ -1398,9 +1436,8 @@ impl<'a> Compiler<'a> {
}
for upvalue in upvalues {
self.resolve_binding(upvalue);
self.emit_op(Op::SetUpvalue);
self.stack_depth -= 1;
self.emit_byte(upvalue.stack_pos);
}
}
FnDeclaration(name) => {
@ -1440,21 +1477,17 @@ impl<'a> Compiler<'a> {
let (Ast::Tuple(members), _) = value.as_ref() else {
unreachable!()
};
for member in members {
for (i, member) in members.iter().enumerate() {
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![];
@ -1511,21 +1544,15 @@ impl<'a> Compiler<'a> {
self.leave_loop();
}
Recur(args) => {
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;
for (i, arg) in args.iter().enumerate() {
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.stack_depth - self.loop_root());
self.emit_byte(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);

View File

@ -100,7 +100,6 @@ pub fn run(src: &'static str) {
let parsed: &'static Spanned<Ast> = Box::leak(Box::new(parse_result.unwrap()));
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,6 +110,8 @@ 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);
@ -143,7 +144,15 @@ pub fn run(src: &'static str) {
pub fn main() {
env::set_var("RUST_BACKTRACE", "1");
let src = r#"
map(inc, [1, 2, 3])
let foo = {
let bar = :bar
let baz = :baz
fn quux () -> {
fn frobulate () -> (bar, baz)
}
}
foo () ()
"#;
run(src);
}

View File

@ -192,15 +192,7 @@ impl std::fmt::Display for Value {
),
Box(value) => write!(f, "box {{ {} }}", value.as_ref().borrow()),
Fn(lfn) => write!(f, "fn {}", lfn.name()),
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")
}
BaseFn(_) => write!(f, "base fn"),
Partial(partial) => write!(f, "fn {}/partial", partial.name),
}
}
@ -243,7 +235,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(_) => format!("{self}"),
BaseFn(_) => "base fn".to_string(),
Nothing => unreachable!(),
}
}

View File

@ -317,11 +317,9 @@ impl Vm {
self.push(Value::Nothing);
self.ip += 1;
}
StoreN => {
let n = self.chunk().bytecode[self.ip + 1] as usize;
for i in (0..n).rev() {
StoreAt => {
let i = self.chunk().bytecode[self.ip + 1] as usize;
self.return_register[i] = self.pop();
}
self.ip += 2;
}
Stash => {
@ -875,10 +873,6 @@ 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) {
@ -930,18 +924,20 @@ impl Vm {
self.ip = 0;
if crate::DEBUG_RUN {}
if crate::DEBUG_RUN {
println!("== tail call 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();
@ -981,6 +977,10 @@ 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,10 +991,6 @@ 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) {
@ -1028,17 +1024,21 @@ 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,6 +1071,10 @@ 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())),
}
@ -1091,12 +1095,12 @@ impl Vm {
self.ip += 1;
}
SetUpvalue => {
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;
let idx = self.chunk().bytecode[self.ip + 1];
self.ip += 2;
let closed_over = self.stack[idx as usize].clone();
if let Value::Fn(lfn) = self.peek() {
lfn.close(closed_over);
}
}
GetUpvalue => {
let idx = self.chunk().bytecode[self.ip + 1];
@ -1107,11 +1111,6 @@ impl Vm {
unreachable!();
}
}
Msg => {
let msg = self.pop();
println!("{msg}");
self.ip += 1;
}
}
}
}