update repeat w/ new jumps

This commit is contained in:
Scott Richmond 2025-06-18 17:50:30 -04:00
parent ffe5d2ad61
commit f6bfe0975b
2 changed files with 18 additions and 49 deletions

View File

@ -1112,8 +1112,7 @@ impl<'a> Compiler<'a> {
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!()
}; };
@ -1155,35 +1154,26 @@ 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);
compiler.emit_op(Op::JumpIfNoMatch); tup_jump_idxes.push(compiler.stub_jump(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);
} }
compiler.emit_op(Op::Jump); let jump_idx = compiler.stub_jump(Op::Jump);
let jump_idx = compiler.len();
compiler.emit_byte(0xff);
for idx in tup_jump_idxes { for idx in tup_jump_idxes {
compiler.chunk.bytecode[idx] = compiler.len() as u8 - idx as u8 - 2; compiler.patch_jump(idx, compiler.len() - idx - 3);
} }
for _ in 0..arity { for _ in 0..arity {
compiler.emit_op(Op::Pop); compiler.emit_op(Op::Pop);
} }
compiler.chunk.bytecode[jump_idx] = compiler.len() as u8 - jump_idx as u8 - 1; compiler.patch_jump(jump_idx, compiler.len() - jump_idx - 3);
let mut no_match_jumps = vec![]; let mut no_match_jumps = vec![];
compiler.emit_op(Op::JumpIfNoMatch); no_match_jumps.push(compiler.stub_jump(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);
compiler.emit_op(Op::JumpIfFalse); no_match_jumps.push(compiler.stub_jump(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);
@ -1196,15 +1186,12 @@ impl<'a> Compiler<'a> {
break; break;
} }
} }
while compiler.stack_depth > 0 { compiler.pop_n(compiler.stack_depth);
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.chunk.bytecode[idx] = compiler.len() as u8 - idx as u8 - 1; compiler.patch_jump(idx, compiler.len() - idx - 3);
} }
// 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);
@ -1245,42 +1232,27 @@ 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);
// self.stack_depth += 1; let jiz_idx = self.stub_jump(Op::JumpIfZero);
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();
// self.emit_op(Op::Pop); let jump_back = self.stub_jump(Op::JumpBack);
self.emit_op(Op::JumpBack);
// set jump points // set jump points
let repeat_end = self.len(); self.patch_jump(jump_back, self.len() - repeat_begin - 2);
self.emit_byte(repeat_end - repeat_begin); self.patch_jump(jiz_idx, self.len() - repeat_begin - 4);
self.chunk.bytecode[repeat_begin + 2] = (repeat_end - repeat_begin - 2) as u8; self.pop();
// 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,13 +73,10 @@ 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 = "
match :foo with { repeat 4 {
:foo if false -> :bar :foo
:bar -> :baz
:foo if true -> :quux
:thing -> :oops
} }
"; ";
run(src); run(src);