Compare commits

..

No commits in common. "f6bfe0975b0695f8108f88bb7c3353fb4f8dee76" and "a5f2e2a9bd770868bbcb776f7f0a8e2da05a9505" have entirely different histories.

4 changed files with 126 additions and 113 deletions

View File

@ -410,7 +410,7 @@ impl<'a> Compiler<'a> {
self.chunk.bytecode.push(low); self.chunk.bytecode.push(low);
} }
fn stub_jump(&mut self, op: Op) -> usize { fn jump_stub(&mut self, op: Op) -> usize {
let out = self.chunk.bytecode.len(); let out = self.chunk.bytecode.len();
self.emit_op(op); self.emit_op(op);
self.emit_byte(0xff); self.emit_byte(0xff);
@ -554,15 +554,9 @@ impl<'a> Compiler<'a> {
} }
fn pop_n(&mut self, n: usize) { fn pop_n(&mut self, n: usize) {
match n { self.emit_op(Op::PopN);
0 => (), self.emit_byte(n);
1 => self.pop(), self.stack_depth -= n;
n => {
self.emit_op(Op::PopN);
self.emit_byte(n);
self.stack_depth -= n;
}
}
} }
fn enter_loop(&mut self) { fn enter_loop(&mut self) {
@ -663,10 +657,10 @@ impl<'a> Compiler<'a> {
} }
If(cond, then, r#else) => { If(cond, then, r#else) => {
self.visit(cond); self.visit(cond);
let jif_idx = self.stub_jump(Op::JumpIfFalse); let jif_idx = self.jump_stub(Op::JumpIfFalse);
self.stack_depth -= 1; self.stack_depth -= 1;
self.visit(then); self.visit(then);
let jump_idx = self.stub_jump(Op::Jump); let jump_idx = self.jump_stub(Op::Jump);
self.visit(r#else); self.visit(r#else);
self.stack_depth -= 1; self.stack_depth -= 1;
let end_idx = self.len(); let end_idx = self.len();
@ -728,7 +722,7 @@ impl<'a> Compiler<'a> {
self.emit_op(Op::MatchTuple); self.emit_op(Op::MatchTuple);
self.emit_byte(members.len()); self.emit_byte(members.len());
// skip everything if tuple lengths don't match // skip everything if tuple lengths don't match
let before_load_tup_idx = self.stub_jump(Op::JumpIfNoMatch); let before_load_tup_idx = self.jump_stub(Op::JumpIfNoMatch);
// set up the per-member conditional logic // set up the per-member conditional logic
let mut jump_idxes = vec![]; let mut jump_idxes = vec![];
@ -749,11 +743,12 @@ impl<'a> Compiler<'a> {
// visit the pattern member // visit the pattern member
self.visit(member); self.visit(member);
// and jump if there's no match // and jump if there's no match
jump_idxes.push(self.stub_jump(Op::JumpIfNoMatch)); jump_idxes.push(self.jump_stub(Op::JumpIfNoMatch));
} }
// if we get here--not having jumped on no match--we're matched; jump the "no match" code // if we get here--not having jumped on no match--we're matched; jump the "no match" code
let jump_idx = self.stub_jump(Op::Jump); self.match_depth = match_depth + members.len();
let jump_idx = self.jump_stub(Op::Jump);
// patch up the previous no match jumps to jump to clean-up code // patch up the previous no match jumps to jump to clean-up code
for idx in jump_idxes { for idx in jump_idxes {
@ -771,52 +766,45 @@ impl<'a> Compiler<'a> {
// patch up the yes-matches unconditional jump // patch up the yes-matches unconditional jump
self.patch_jump(jump_idx, self.len() - jump_idx - 3); self.patch_jump(jump_idx, self.len() - jump_idx - 3);
// finally, for any further matches (e.g. nested lists/tuples)
// add increase the match depth, since we've added a bunch
// of bindings to the stack
self.match_depth = match_depth + members.len();
} }
ListPattern(members) => { ListPattern(members) => {
self.emit_op(Op::MatchList); self.emit_op(Op::MatchList);
self.emit_byte(members.len()); self.emit_byte(members.len());
let before_load_tup_idx = self.stub_jump(Op::JumpIfNoMatch); self.emit_op(Op::JumpIfNoMatch);
let before_load_list_idx = self.len();
self.emit_byte(0xff);
let mut jump_idxes = vec![]; let mut jump_idxes = vec![];
let match_depth = self.match_depth; self.match_depth += members.len();
self.match_depth = members.len();
self.emit_op(Op::LoadList); self.emit_op(Op::LoadList);
self.stack_depth += members.len(); self.stack_depth += members.len();
for member in members { for member in members {
self.match_depth -= 1; self.match_depth -= 1;
self.emit_op(Op::MatchDepth); self.emit_op(Op::MatchDepth);
self.emit_byte(self.match_depth); self.emit_byte(self.match_depth);
self.visit(member); self.visit(member);
jump_idxes.push(self.stub_jump(Op::JumpIfNoMatch)); self.emit_op(Op::JumpIfNoMatch);
jump_idxes.push(self.len());
self.emit_byte(0xff);
} }
self.emit_op(Op::Jump);
let jump_idx = self.stub_jump(Op::Jump); let jump_idx = self.len();
self.emit_byte(0xff);
for idx in jump_idxes { for idx in jump_idxes {
self.patch_jump(idx, self.len() - idx - 2) self.chunk.bytecode[idx] = (self.len() - idx) as u8 - 1;
} }
for _ in 0..members.len() {
self.emit_op(Op::PopN); self.emit_op(Op::Pop);
self.emit_byte(members.len()); }
self.chunk.bytecode[before_load_list_idx] =
self.patch_jump(before_load_tup_idx, self.len() - before_load_tup_idx - 3); (self.len() - before_load_list_idx) as u8 - 1;
self.chunk.bytecode[jump_idx] = (self.len() - jump_idx) as u8 - 1;
self.patch_jump(jump_idx, self.len() - jump_idx - 3);
self.match_depth = match_depth + members.len();
} }
DictPattern(pairs) => { DictPattern(pairs) => {
self.emit_op(Op::MatchDict); self.emit_op(Op::MatchDict);
self.emit_byte(pairs.len()); self.emit_byte(pairs.len());
let before_load_dict_idx = self.stub_jump(Op::JumpIfNoMatch); self.emit_op(Op::JumpIfNoMatch);
let before_load_dict_idx = self.len();
self.emit_byte(0xff);
let mut jump_idxes = vec![]; let mut jump_idxes = vec![];
let dict_stack_pos = self.stack_depth - 1; let dict_stack_pos = self.stack_depth - 1;
for pair in pairs { for pair in pairs {
@ -827,19 +815,22 @@ impl<'a> Compiler<'a> {
self.emit_op(Op::LoadDictValue); self.emit_op(Op::LoadDictValue);
self.emit_byte(dict_stack_pos); self.emit_byte(dict_stack_pos);
self.visit(pattern); self.visit(pattern);
jump_idxes.push(self.stub_jump(Op::JumpIfNoMatch)); self.emit_op(Op::JumpIfNoMatch);
jump_idxes.push(self.len());
self.emit_byte(0xff);
} }
let jump_idx = self.stub_jump(Op::Jump); self.emit_op(Op::Jump);
let jump_idx = self.len();
self.emit_byte(0xff);
for idx in jump_idxes { for idx in jump_idxes {
self.patch_jump(idx, self.len() - idx - 2); self.chunk.bytecode[idx] = (self.len() - idx) as u8 - 1;
} }
for _ in 0..pairs.len() {
self.emit_op(Op::PopN); self.emit_op(Op::Pop);
self.emit_byte(pairs.len()); }
self.chunk.bytecode[before_load_dict_idx] =
self.patch_jump(before_load_dict_idx, self.len() - before_load_dict_idx - 3); (self.len() - before_load_dict_idx) as u8 - 1;
self.patch_jump(jump_idx, self.len() - jump_idx - 3); self.chunk.bytecode[jump_idx] = (self.len() - jump_idx) as u8 - 1;
} }
Splattern(..) => { Splattern(..) => {
todo!() todo!()
@ -873,7 +864,9 @@ impl<'a> Compiler<'a> {
self.emit_op(Op::MatchString); self.emit_op(Op::MatchString);
self.emit_byte(pattern_idx); self.emit_byte(pattern_idx);
let jnm_idx = self.stub_jump(Op::JumpIfNoMatch); self.emit_op(Op::JumpIfNoMatch);
let jnm_idx = self.len();
self.emit_byte(0xff);
self.emit_op(Op::PushStringMatches); self.emit_op(Op::PushStringMatches);
self.emit_byte(pattern_idx); self.emit_byte(pattern_idx);
@ -889,7 +882,7 @@ impl<'a> Compiler<'a> {
self.stack_depth += 1; self.stack_depth += 1;
} }
self.patch_jump(jnm_idx, self.len() - jnm_idx - 3); self.chunk.bytecode[jnm_idx] = (self.len() - jnm_idx - 1) as u8;
} }
PairPattern(_, _) => unreachable!(), PairPattern(_, _) => unreachable!(),
Tuple(members) => { Tuple(members) => {
@ -957,10 +950,12 @@ impl<'a> Compiler<'a> {
for arg in args { for arg in args {
self.visit(arg); self.visit(arg);
self.emit_op(Op::Stash); self.emit_op(Op::Stash);
jump_idxes.push(self.stub_jump(Op::JumpIfTrue)); self.emit_op(Op::JumpIfTrue);
jump_idxes.push(self.len());
self.emit_byte(0xff);
} }
for idx in jump_idxes { for idx in jump_idxes {
self.patch_jump(idx, self.len() - idx); self.chunk.bytecode[idx] = (self.len() - idx + 2) as u8;
} }
self.emit_op(Op::Load); self.emit_op(Op::Load);
} else { } else {
@ -975,10 +970,12 @@ impl<'a> Compiler<'a> {
for arg in args { for arg in args {
self.visit(arg); self.visit(arg);
self.emit_op(Op::Stash); self.emit_op(Op::Stash);
jump_idxes.push(self.stub_jump(Op::JumpIfFalse)); self.emit_op(Op::JumpIfFalse);
jump_idxes.push(self.len());
self.emit_byte(0xff);
} }
for idx in jump_idxes { for idx in jump_idxes {
self.patch_jump(idx, self.len() - idx); self.chunk.bytecode[idx] = (self.len() - idx + 2) as u8;
} }
self.emit_op(Op::Load); self.emit_op(Op::Load);
} else { } else {
@ -1048,16 +1045,20 @@ impl<'a> Compiler<'a> {
let mut clauses = clauses.iter(); let mut clauses = clauses.iter();
while let Some((WhenClause(cond, body), _)) = clauses.next() { while let Some((WhenClause(cond, body), _)) = clauses.next() {
self.visit(cond.as_ref()); self.visit(cond.as_ref());
let jif_jump_idx = self.stub_jump(Op::JumpIfFalse); self.emit_op(Op::JumpIfFalse);
let jif_jump_idx = self.len();
self.emit_byte(0xff);
self.stack_depth -= 1; self.stack_depth -= 1;
self.visit(body); self.visit(body);
self.stack_depth -= 1; self.stack_depth -= 1;
jump_idxes.push(self.stub_jump(Op::Jump)); self.emit_op(Op::Jump);
self.patch_jump(jif_jump_idx, self.len() - jif_jump_idx - 3); jump_idxes.push(self.len());
self.emit_byte(0xff);
self.chunk.bytecode[jif_jump_idx] = (self.len() - jif_jump_idx) as u8 - 1;
} }
self.emit_op(Op::PanicNoWhen); self.emit_op(Op::PanicNoWhen);
for idx in jump_idxes { for idx in jump_idxes {
self.patch_jump(idx, self.len() - idx - 3); self.chunk.bytecode[idx] = (self.len() - idx) as u8 - 1;
} }
self.stack_depth += 1; self.stack_depth += 1;
} }
@ -1072,12 +1073,16 @@ impl<'a> Compiler<'a> {
self.scope_depth += 1; self.scope_depth += 1;
self.match_depth = 0; self.match_depth = 0;
self.visit(pattern); self.visit(pattern);
no_match_jumps.push(self.stub_jump(Op::JumpIfNoMatch)); self.emit_op(Op::JumpIfNoMatch);
no_match_jumps.push(self.len());
self.emit_byte(0xff);
if guard.is_some() { if guard.is_some() {
let guard_expr: &'static Spanned<Ast> = let guard_expr: &'static Spanned<Ast> =
Box::leak(Box::new(guard.clone().unwrap())); Box::leak(Box::new(guard.clone().unwrap()));
self.visit(guard_expr); self.visit(guard_expr);
no_match_jumps.push(self.stub_jump(Op::JumpIfFalse)); self.emit_op(Op::JumpIfFalse);
no_match_jumps.push(self.len());
self.emit_byte(0xff);
self.stack_depth -= 1; self.stack_depth -= 1;
} }
self.visit(body); self.visit(body);
@ -1090,29 +1095,31 @@ impl<'a> Compiler<'a> {
break; break;
} }
} }
self.pop_n(self.stack_depth - stack_depth); while self.stack_depth > stack_depth {
jump_idxes.push(self.stub_jump(Op::Jump)); self.pop();
}
self.emit_op(Op::Jump);
jump_idxes.push(self.len());
self.emit_byte(0xff);
for idx in no_match_jumps { for idx in no_match_jumps {
self.patch_jump(idx, self.len() - idx - 3); self.chunk.bytecode[idx] = (self.len() - idx) as u8 - 1;
} }
} }
self.emit_op(Op::PanicNoMatch); self.emit_op(Op::PanicNoMatch);
for idx in jump_idxes { for idx in jump_idxes {
self.patch_jump(idx, self.len() - idx - 3); self.chunk.bytecode[idx] = (self.len() - idx) as u8 - 1;
// self.chunk.bytecode[idx] = (self.len() - idx) as u8 - 1; }
while self.stack_depth > stack_depth {
self.pop();
} }
self.pop_n(self.stack_depth - stack_depth);
// while self.stack_depth > stack_depth {
// self.pop();
// }
self.emit_op(Op::Load); self.emit_op(Op::Load);
self.stack_depth += 1; self.stack_depth += 1;
} }
MatchClause(..) => unreachable!(), MatchClause(..) => unreachable!(),
Fn(name, body, doc) => { Fn(name, body, doc) => {
let name = if name.is_empty() { "anonymous" } else { name }; let name = if name.is_empty() { "anonymous" } else { name };
// first, declare the function
// TODO: or, check if the function has already been declared!
let FnBody(fn_body) = &body.as_ref().0 else { let FnBody(fn_body) = &body.as_ref().0 else {
unreachable!() unreachable!()
}; };
@ -1154,26 +1161,35 @@ impl<'a> Compiler<'a> {
compiler.emit_op(Op::MatchDepth); compiler.emit_op(Op::MatchDepth);
compiler.emit_byte(compiler.match_depth); compiler.emit_byte(compiler.match_depth);
compiler.visit(member); compiler.visit(member);
tup_jump_idxes.push(compiler.stub_jump(Op::JumpIfNoMatch)); compiler.emit_op(Op::JumpIfNoMatch);
tup_jump_idxes.push(compiler.len());
compiler.emit_byte(0xff);
} }
if pattern.is_empty() { if pattern.is_empty() {
compiler.emit_op(Op::Match); compiler.emit_op(Op::Match);
} }
let jump_idx = compiler.stub_jump(Op::Jump); compiler.emit_op(Op::Jump);
let jump_idx = compiler.len();
compiler.emit_byte(0xff);
for idx in tup_jump_idxes { for idx in tup_jump_idxes {
compiler.patch_jump(idx, compiler.len() - idx - 3); compiler.chunk.bytecode[idx] = compiler.len() as u8 - idx as u8 - 2;
} }
for _ in 0..arity { for _ in 0..arity {
compiler.emit_op(Op::Pop); compiler.emit_op(Op::Pop);
} }
compiler.patch_jump(jump_idx, compiler.len() - jump_idx - 3); compiler.chunk.bytecode[jump_idx] = compiler.len() as u8 - jump_idx as u8 - 1;
let mut no_match_jumps = vec![]; let mut no_match_jumps = vec![];
no_match_jumps.push(compiler.stub_jump(Op::JumpIfNoMatch)); compiler.emit_op(Op::JumpIfNoMatch);
// let jnm_idx = compiler.len();
no_match_jumps.push(compiler.len());
compiler.emit_byte(0xff);
if guard.is_some() { if guard.is_some() {
let guard_expr: &'static Spanned<Ast> = let guard_expr: &'static Spanned<Ast> =
Box::leak(Box::new(guard.clone().unwrap())); Box::leak(Box::new(guard.clone().unwrap()));
compiler.visit(guard_expr); compiler.visit(guard_expr);
no_match_jumps.push(compiler.stub_jump(Op::JumpIfFalse)); compiler.emit_op(Op::JumpIfFalse);
no_match_jumps.push(self.len());
compiler.emit_byte(0xff);
compiler.stack_depth -= 1; compiler.stack_depth -= 1;
} }
compiler.visit(clause_body); compiler.visit(clause_body);
@ -1186,12 +1202,15 @@ impl<'a> Compiler<'a> {
break; break;
} }
} }
compiler.pop_n(compiler.stack_depth); while compiler.stack_depth > 0 {
compiler.pop();
}
compiler.stack_depth = 0; compiler.stack_depth = 0;
compiler.emit_op(Op::Return); compiler.emit_op(Op::Return);
for idx in no_match_jumps { for idx in no_match_jumps {
compiler.patch_jump(idx, compiler.len() - idx - 3); compiler.chunk.bytecode[idx] = compiler.len() as u8 - idx as u8 - 1;
} }
// compiler.chunk.bytecode[jnm_idx] = compiler.len() as u8 - jnm_idx as u8 - 1;
compiler.scope_depth -= 1; compiler.scope_depth -= 1;
std::mem::swap(&mut compiler.upvalues, &mut upvalues); std::mem::swap(&mut compiler.upvalues, &mut upvalues);
@ -1232,27 +1251,42 @@ impl<'a> Compiler<'a> {
self.bind(name); self.bind(name);
} }
FnBody(_) => unreachable!(), FnBody(_) => unreachable!(),
// TODO: add a check to make sure times >= 0
// TODO: fix this so that the algorithm is actually correct
// * truncate
// * check that it's 0 or more, panic if not
// * jump if 0 to end of loop
// * body
// * pop
// * decrement counter (which is now at the top of the stack)
// * jump back to jump if 0 instruction
Repeat(times, body) => { Repeat(times, body) => {
self.visit(times); self.visit(times);
self.emit_op(Op::Truncate); self.emit_op(Op::Truncate);
// skip the decrement the first time // skip the decrement the first time
self.emit_op(Op::Jump); self.emit_op(Op::Jump);
self.emit_byte(0);
self.emit_byte(1); self.emit_byte(1);
// begin repeat // begin repeat
self.emit_op(Op::Decrement); self.emit_op(Op::Decrement);
let repeat_begin = self.len(); let repeat_begin = self.len();
self.emit_op(Op::Duplicate); self.emit_op(Op::Duplicate);
let jiz_idx = self.stub_jump(Op::JumpIfZero); // self.stack_depth += 1;
self.emit_op(Op::JumpIfZero);
self.emit_byte(0xff);
// compile the body // compile the body
self.visit(body); self.visit(body);
// pop whatever value the body returns // pop whatever value the body returns
self.pop(); self.pop();
let jump_back = self.stub_jump(Op::JumpBack); // self.emit_op(Op::Pop);
self.emit_op(Op::JumpBack);
// set jump points // set jump points
self.patch_jump(jump_back, self.len() - repeat_begin - 2); let repeat_end = self.len();
self.patch_jump(jiz_idx, self.len() - repeat_begin - 4); self.emit_byte(repeat_end - repeat_begin);
self.pop(); self.chunk.bytecode[repeat_begin + 2] = (repeat_end - repeat_begin - 2) as u8;
// pop the counter
// self.pop();
// self.emit_op(Op::Pop);
// and emit nil
self.emit_constant(Value::Nil); self.emit_constant(Value::Nil);
} }
Loop(value, clauses) => { Loop(value, clauses) => {

View File

@ -73,11 +73,9 @@ 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 = " let src = "
repeat 4 { let ((1)) = ((1))
:foo
}
"; ";
run(src); run(src);
} }

View File

@ -45,13 +45,6 @@ impl LFn {
} }
} }
pub fn accepts(&self, arity: u8) -> bool {
match self {
LFn::Defined { chunks, .. } => chunks.iter().any(|(a, _)| *a == arity),
LFn::Declared { .. } => unreachable!(),
}
}
pub fn name(&self) -> &'static str { pub fn name(&self) -> &'static str {
match self { match self {
LFn::Declared { name } | LFn::Defined { name, .. } => name, LFn::Declared { name } | LFn::Defined { name, .. } => name,
@ -59,6 +52,7 @@ impl LFn {
} }
pub fn chunk(&self, arity: u8) -> &Chunk { pub fn chunk(&self, arity: u8) -> &Chunk {
// println!("Getting chunk of {arity} from {:?}", self);
match self { match self {
LFn::Declared { .. } => unreachable!(), LFn::Declared { .. } => unreachable!(),
LFn::Defined { chunks, .. } => &chunks.iter().find(|(a, _)| *a == arity).unwrap().1, LFn::Defined { chunks, .. } => &chunks.iter().find(|(a, _)| *a == arity).unwrap().1,
@ -274,11 +268,4 @@ impl Value {
Partial(..) => "fn", Partial(..) => "fn",
} }
} }
pub fn as_fn(&self) -> &LFn {
match self {
Value::Fn(inner) => inner.as_ref(),
_ => unreachable!(),
}
}
} }

View File

@ -790,12 +790,6 @@ impl Vm {
match val { match val {
Value::Fn(_) => { Value::Fn(_) => {
if !val.as_fn().accepts(arity) {
return self.panic_with(format!(
"wrong number of arguments to {} passing {arity} args",
val.show()
));
}
let mut frame = CallFrame { let mut frame = CallFrame {
function: val, function: val,
arity, arity,