add match_depth to vm

This commit is contained in:
Scott Richmond 2024-12-27 00:22:01 -05:00
parent 6f582bff06
commit 8908630a21
3 changed files with 53 additions and 11 deletions

View File

@ -141,6 +141,7 @@ pub struct Compiler {
pub span: SimpleSpan, pub span: SimpleSpan,
pub src: &'static str, pub src: &'static str,
pub name: &'static str, pub name: &'static str,
loop_idxes: Vec<usize>,
} }
fn is_binding(expr: &Spanned<Ast>) -> bool { fn is_binding(expr: &Spanned<Ast>) -> bool {
@ -172,6 +173,7 @@ impl Compiler {
nodes: vec![], nodes: vec![],
ast: &ast.0, ast: &ast.0,
span: ast.1, span: ast.1,
loop_idxes: vec![],
src, src,
name, 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) { pub fn compile(&mut self) {
use Ast::*; use Ast::*;
match self.ast { match self.ast {
@ -472,7 +486,6 @@ impl Compiler {
self.visit(scrutinee.as_ref()); self.visit(scrutinee.as_ref());
let mut jump_idxes = vec![]; let mut jump_idxes = vec![];
let mut clauses = clauses.iter(); let mut clauses = clauses.iter();
// TODO: add guard checking
while let Some((MatchClause(pattern, guard, body), _)) = clauses.next() { while let Some((MatchClause(pattern, guard, body), _)) = clauses.next() {
self.scope_depth += 1; self.scope_depth += 1;
self.visit(pattern); self.visit(pattern);
@ -592,14 +605,38 @@ impl Compiler {
// and emit nil // and emit nil
self.emit_constant(Value::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(..) Interpolated(..)
| Arguments(..) | Arguments(..)
| Placeholder | Placeholder
| Panic(..) | Panic(..)
| Do(..) | Do(..)
| Splat(..) | Splat(..)
| Loop(..)
| Recur(..)
| InterpolatedPattern(..) | InterpolatedPattern(..)
| AsPattern(..) | AsPattern(..)
| Splattern(..) | Splattern(..)

View File

@ -69,9 +69,8 @@ pub fn run(src: &'static str) {
pub fn main() { pub fn main() {
let src = " let src = "
match :foo with { match :foo with {
:foo if nil -> :oops :bar -> :no
:foo if true -> :yay! :foo -> :yes
:bar -> :thing
} }
"; ";
run(src); run(src);

View File

@ -36,6 +36,7 @@ pub struct Vm<'a> {
pub ip: usize, pub ip: usize,
pub return_register: Value, pub return_register: Value,
pub matches: bool, pub matches: bool,
pub match_depth: u8,
} }
impl<'a> Vm<'a> { impl<'a> Vm<'a> {
@ -46,6 +47,7 @@ impl<'a> Vm<'a> {
ip: 0, ip: 0,
return_register: Value::Nil, return_register: Value::Nil,
matches: false, matches: false,
match_depth: 0,
} }
} }
@ -174,6 +176,7 @@ impl<'a> Vm<'a> {
} }
ResetMatch => { ResetMatch => {
self.matches = false; self.matches = false;
self.match_depth = 0;
self.ip += 1; self.ip += 1;
self.interpret() self.interpret()
} }
@ -183,21 +186,24 @@ impl<'a> Vm<'a> {
self.interpret() self.interpret()
} }
MatchNil => { 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.matches = true;
}; };
self.ip += 1; self.ip += 1;
self.interpret() self.interpret()
} }
MatchTrue => { 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.matches = true;
}; };
self.ip += 1; self.ip += 1;
self.interpret() self.interpret()
} }
MatchFalse => { 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.matches = true;
} }
self.ip += 1; self.ip += 1;
@ -213,8 +219,8 @@ impl<'a> Vm<'a> {
} }
MatchConstant => { MatchConstant => {
let const_idx = self.chunk.bytecode[self.ip + 1]; let const_idx = self.chunk.bytecode[self.ip + 1];
let value = self.stack.last().unwrap(); let idx = self.stack.len() - self.match_depth as usize - 1;
self.matches = *value == self.chunk.constants[const_idx as usize]; self.matches = self.stack[idx] == self.chunk.constants[const_idx as usize];
self.ip += 2; self.ip += 2;
self.interpret() self.interpret()
} }