From 23298c853839504b98951a43df570e721ad6b225 Mon Sep 17 00:00:00 2001 From: Scott Richmond Date: Wed, 18 Jun 2025 15:24:30 -0400 Subject: [PATCH] match now uses new jump; micro-optimize pop_n --- src/compiler.rs | 95 ++++++++++++++++++++++--------------------------- src/main.rs | 7 +++- 2 files changed, 49 insertions(+), 53 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index f2f61c4..210b727 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -410,7 +410,7 @@ impl<'a> Compiler<'a> { self.chunk.bytecode.push(low); } - fn jump_stub(&mut self, op: Op) -> usize { + fn stub_jump(&mut self, op: Op) -> usize { let out = self.chunk.bytecode.len(); self.emit_op(op); self.emit_byte(0xff); @@ -554,9 +554,15 @@ impl<'a> Compiler<'a> { } fn pop_n(&mut self, n: usize) { - self.emit_op(Op::PopN); - self.emit_byte(n); - self.stack_depth -= n; + match n { + 0 => (), + 1 => self.pop(), + n => { + self.emit_op(Op::PopN); + self.emit_byte(n); + self.stack_depth -= n; + } + } } fn enter_loop(&mut self) { @@ -657,10 +663,10 @@ impl<'a> Compiler<'a> { } If(cond, then, r#else) => { self.visit(cond); - let jif_idx = self.jump_stub(Op::JumpIfFalse); + let jif_idx = self.stub_jump(Op::JumpIfFalse); self.stack_depth -= 1; self.visit(then); - let jump_idx = self.jump_stub(Op::Jump); + let jump_idx = self.stub_jump(Op::Jump); self.visit(r#else); self.stack_depth -= 1; let end_idx = self.len(); @@ -722,7 +728,7 @@ impl<'a> Compiler<'a> { self.emit_op(Op::MatchTuple); self.emit_byte(members.len()); // skip everything if tuple lengths don't match - let before_load_tup_idx = self.jump_stub(Op::JumpIfNoMatch); + let before_load_tup_idx = self.stub_jump(Op::JumpIfNoMatch); // set up the per-member conditional logic let mut jump_idxes = vec![]; @@ -743,11 +749,11 @@ impl<'a> Compiler<'a> { // visit the pattern member self.visit(member); // and jump if there's no match - jump_idxes.push(self.jump_stub(Op::JumpIfNoMatch)); + jump_idxes.push(self.stub_jump(Op::JumpIfNoMatch)); } // if we get here--not having jumped on no match--we're matched; jump the "no match" code - let jump_idx = self.jump_stub(Op::Jump); + let jump_idx = self.stub_jump(Op::Jump); // patch up the previous no match jumps to jump to clean-up code for idx in jump_idxes { @@ -774,7 +780,7 @@ impl<'a> Compiler<'a> { ListPattern(members) => { self.emit_op(Op::MatchList); self.emit_byte(members.len()); - let before_load_tup_idx = self.jump_stub(Op::JumpIfNoMatch); + let before_load_tup_idx = self.stub_jump(Op::JumpIfNoMatch); let mut jump_idxes = vec![]; let match_depth = self.match_depth; @@ -788,10 +794,10 @@ impl<'a> Compiler<'a> { self.emit_op(Op::MatchDepth); self.emit_byte(self.match_depth); self.visit(member); - jump_idxes.push(self.jump_stub(Op::JumpIfNoMatch)); + jump_idxes.push(self.stub_jump(Op::JumpIfNoMatch)); } - let jump_idx = self.jump_stub(Op::Jump); + let jump_idx = self.stub_jump(Op::Jump); for idx in jump_idxes { self.patch_jump(idx, self.len() - idx - 2) @@ -809,7 +815,7 @@ impl<'a> Compiler<'a> { DictPattern(pairs) => { self.emit_op(Op::MatchDict); self.emit_byte(pairs.len()); - let before_load_dict_idx = self.jump_stub(Op::JumpIfNoMatch); + let before_load_dict_idx = self.stub_jump(Op::JumpIfNoMatch); let mut jump_idxes = vec![]; let dict_stack_pos = self.stack_depth - 1; @@ -821,9 +827,9 @@ impl<'a> Compiler<'a> { self.emit_op(Op::LoadDictValue); self.emit_byte(dict_stack_pos); self.visit(pattern); - jump_idxes.push(self.jump_stub(Op::JumpIfNoMatch)); + jump_idxes.push(self.stub_jump(Op::JumpIfNoMatch)); } - let jump_idx = self.jump_stub(Op::Jump); + let jump_idx = self.stub_jump(Op::Jump); for idx in jump_idxes { self.patch_jump(idx, self.len() - idx - 2); @@ -867,9 +873,7 @@ impl<'a> Compiler<'a> { self.emit_op(Op::MatchString); self.emit_byte(pattern_idx); - self.emit_op(Op::JumpIfNoMatch); - let jnm_idx = self.len(); - self.emit_byte(0xff); + let jnm_idx = self.stub_jump(Op::JumpIfNoMatch); self.emit_op(Op::PushStringMatches); self.emit_byte(pattern_idx); @@ -885,7 +889,7 @@ impl<'a> Compiler<'a> { self.stack_depth += 1; } - self.chunk.bytecode[jnm_idx] = (self.len() - jnm_idx - 1) as u8; + self.patch_jump(jnm_idx, self.len() - jnm_idx - 3); } PairPattern(_, _) => unreachable!(), Tuple(members) => { @@ -953,12 +957,10 @@ impl<'a> Compiler<'a> { for arg in args { self.visit(arg); self.emit_op(Op::Stash); - self.emit_op(Op::JumpIfTrue); - jump_idxes.push(self.len()); - self.emit_byte(0xff); + jump_idxes.push(self.stub_jump(Op::JumpIfTrue)); } for idx in jump_idxes { - self.chunk.bytecode[idx] = (self.len() - idx + 2) as u8; + self.patch_jump(idx, self.len() - idx); } self.emit_op(Op::Load); } else { @@ -973,12 +975,10 @@ impl<'a> Compiler<'a> { for arg in args { self.visit(arg); self.emit_op(Op::Stash); - self.emit_op(Op::JumpIfFalse); - jump_idxes.push(self.len()); - self.emit_byte(0xff); + jump_idxes.push(self.stub_jump(Op::JumpIfFalse)); } for idx in jump_idxes { - self.chunk.bytecode[idx] = (self.len() - idx + 2) as u8; + self.patch_jump(idx, self.len() - idx); } self.emit_op(Op::Load); } else { @@ -1048,20 +1048,16 @@ impl<'a> Compiler<'a> { let mut clauses = clauses.iter(); while let Some((WhenClause(cond, body), _)) = clauses.next() { self.visit(cond.as_ref()); - self.emit_op(Op::JumpIfFalse); - let jif_jump_idx = self.len(); - self.emit_byte(0xff); + let jif_jump_idx = self.stub_jump(Op::JumpIfFalse); self.stack_depth -= 1; self.visit(body); self.stack_depth -= 1; - self.emit_op(Op::Jump); - jump_idxes.push(self.len()); - self.emit_byte(0xff); - self.chunk.bytecode[jif_jump_idx] = (self.len() - jif_jump_idx) as u8 - 1; + jump_idxes.push(self.stub_jump(Op::Jump)); + self.patch_jump(jif_jump_idx, self.len() - jif_jump_idx - 3); } self.emit_op(Op::PanicNoWhen); for idx in jump_idxes { - self.chunk.bytecode[idx] = (self.len() - idx) as u8 - 1; + self.patch_jump(idx, self.len() - idx - 3); } self.stack_depth += 1; } @@ -1076,16 +1072,12 @@ impl<'a> Compiler<'a> { self.scope_depth += 1; self.match_depth = 0; self.visit(pattern); - self.emit_op(Op::JumpIfNoMatch); - no_match_jumps.push(self.len()); - self.emit_byte(0xff); + no_match_jumps.push(self.stub_jump(Op::JumpIfNoMatch)); if guard.is_some() { let guard_expr: &'static Spanned = Box::leak(Box::new(guard.clone().unwrap())); self.visit(guard_expr); - self.emit_op(Op::JumpIfFalse); - no_match_jumps.push(self.len()); - self.emit_byte(0xff); + no_match_jumps.push(self.stub_jump(Op::JumpIfFalse)); self.stack_depth -= 1; } self.visit(body); @@ -1098,23 +1090,22 @@ impl<'a> Compiler<'a> { break; } } - while self.stack_depth > stack_depth { - self.pop(); - } - self.emit_op(Op::Jump); - jump_idxes.push(self.len()); - self.emit_byte(0xff); + self.pop_n(self.stack_depth - stack_depth); + jump_idxes.push(self.stub_jump(Op::Jump)); for idx in no_match_jumps { - self.chunk.bytecode[idx] = (self.len() - idx) as u8 - 1; + self.patch_jump(idx, self.len() - idx - 3); } } self.emit_op(Op::PanicNoMatch); + for idx in jump_idxes { - self.chunk.bytecode[idx] = (self.len() - idx) as u8 - 1; - } - while self.stack_depth > stack_depth { - self.pop(); + self.patch_jump(idx, self.len() - idx - 3); + // self.chunk.bytecode[idx] = (self.len() - idx) as u8 - 1; } + self.pop_n(self.stack_depth - stack_depth); + // while self.stack_depth > stack_depth { + // self.pop(); + // } self.emit_op(Op::Load); self.stack_depth += 1; } diff --git a/src/main.rs b/src/main.rs index 94b10ce..d02f13c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -75,7 +75,12 @@ pub fn run(src: &'static str) { pub fn main() { // env::set_var("RUST_BACKTRACE", "1"); let src = " -let #{:a 1, :b (2, #{:c 3})} = #{:a 1, :b (1, #{:c 3})} +match :foo with { + :foo if false -> :bar + :bar -> :baz + :foo if true -> :quux + :thing -> :oops +} "; run(src); }