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 src: &'static str,
pub name: &'static str,
loop_idxes: Vec<usize>,
}
fn is_binding(expr: &Spanned<Ast>) -> 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(..)

View File

@ -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);

View File

@ -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()
}