From 8908630a21300f8fb1daafdb135ecfae1d7ab43d Mon Sep 17 00:00:00 2001 From: Scott Richmond Date: Fri, 27 Dec 2024 00:22:01 -0500 Subject: [PATCH] add match_depth to vm --- src/compiler.rs | 43 ++++++++++++++++++++++++++++++++++++++++--- src/main.rs | 5 ++--- src/vm.rs | 16 +++++++++++----- 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 40f56b5..64425df 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -141,6 +141,7 @@ pub struct Compiler { pub span: SimpleSpan, pub src: &'static str, pub name: &'static str, + loop_idxes: Vec, } fn is_binding(expr: &Spanned) -> bool { @@ -172,6 +173,7 @@ impl Compiler { nodes: vec![], ast: &ast.0, span: ast.1, + loop_idxes: vec![], src, name, } @@ -253,6 +255,18 @@ impl Compiler { }); } + fn enter_loop(&mut self) { + self.loop_idxes.push(self.len()); + } + + fn leave_loop(&mut self) { + self.loop_idxes.pop(); + } + + fn loop_idx(&mut self) -> usize { + *self.loop_idxes.last().unwrap() + } + pub fn compile(&mut self) { use Ast::*; match self.ast { @@ -472,7 +486,6 @@ impl Compiler { self.visit(scrutinee.as_ref()); let mut jump_idxes = vec![]; let mut clauses = clauses.iter(); - // TODO: add guard checking while let Some((MatchClause(pattern, guard, body), _)) = clauses.next() { self.scope_depth += 1; self.visit(pattern); @@ -592,14 +605,38 @@ impl Compiler { // and emit nil self.emit_constant(Value::Nil); } + Loop(value, clauses) => { + //algo: + //first, put the values on the stack + let (Ast::Tuple(members), _) = value.as_ref() else { + unreachable!() + }; + for member in members { + self.visit(member); + } + let arity = members.len(); + //then, save the beginning of the loop + self.enter_loop(); + self.emit_op(Op::ResetMatch); + //next, compile each clause: + let mut clauses = clauses.iter(); + while let Some((Ast::MatchClause(pattern, _, body), _)) = clauses.next() { + self.scope_depth += 1; + let (Ast::TuplePattern(members), _) = pattern.as_ref() else { + unreachable!() + }; + } + //match against the values on the stack + //we know the (fixed) arity, so we should know where to look + //compile the clauses exactly as in `match` + } + Recur(args) => {} Interpolated(..) | Arguments(..) | Placeholder | Panic(..) | Do(..) | Splat(..) - | Loop(..) - | Recur(..) | InterpolatedPattern(..) | AsPattern(..) | Splattern(..) diff --git a/src/main.rs b/src/main.rs index ee5ddf1..b539c79 100644 --- a/src/main.rs +++ b/src/main.rs @@ -69,9 +69,8 @@ pub fn run(src: &'static str) { pub fn main() { let src = " match :foo with { - :foo if nil -> :oops - :foo if true -> :yay! - :bar -> :thing + :bar -> :no + :foo -> :yes } "; run(src); diff --git a/src/vm.rs b/src/vm.rs index 16b4843..c201906 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -36,6 +36,7 @@ pub struct Vm<'a> { pub ip: usize, pub return_register: Value, pub matches: bool, + pub match_depth: u8, } impl<'a> Vm<'a> { @@ -46,6 +47,7 @@ impl<'a> Vm<'a> { ip: 0, return_register: Value::Nil, matches: false, + match_depth: 0, } } @@ -174,6 +176,7 @@ impl<'a> Vm<'a> { } ResetMatch => { self.matches = false; + self.match_depth = 0; self.ip += 1; self.interpret() } @@ -183,21 +186,24 @@ impl<'a> Vm<'a> { self.interpret() } MatchNil => { - if *self.stack.last().unwrap() == Value::Nil { + let idx = self.stack.len() - self.match_depth as usize - 1; + if self.stack[idx] == Value::Nil { self.matches = true; }; self.ip += 1; self.interpret() } MatchTrue => { - if *self.stack.last().unwrap() == Value::True { + let idx = self.stack.len() - self.match_depth as usize - 1; + if self.stack[idx] == Value::True { self.matches = true; }; self.ip += 1; self.interpret() } MatchFalse => { - if *self.stack.last().unwrap() == Value::False { + let idx = self.stack.len() - self.match_depth as usize - 1; + if self.stack[idx] == Value::False { self.matches = true; } self.ip += 1; @@ -213,8 +219,8 @@ impl<'a> Vm<'a> { } MatchConstant => { let const_idx = self.chunk.bytecode[self.ip + 1]; - let value = self.stack.last().unwrap(); - self.matches = *value == self.chunk.constants[const_idx as usize]; + let idx = self.stack.len() - self.match_depth as usize - 1; + self.matches = self.stack[idx] == self.chunk.constants[const_idx as usize]; self.ip += 2; self.interpret() }