get simple match forms done

This commit is contained in:
Scott Richmond 2024-12-22 19:33:59 -05:00
parent d943185db8
commit be23ee6c44
3 changed files with 63 additions and 17 deletions

View File

@ -31,6 +31,8 @@ pub enum Op {
PushBox,
GetKey,
PanicNoWhen,
JumpIfNoMatch,
PanicNoMatch,
}
impl std::fmt::Display for Op {
@ -61,6 +63,8 @@ impl std::fmt::Display for Op {
PushBox => "push_box",
GetKey => "get_key",
PanicNoWhen => "panic_no_when",
JumpIfNoMatch => "jump_if_no_match",
PanicNoMatch => "panic_no_match",
};
write!(f, "{rep}")
}
@ -393,6 +397,40 @@ impl<'a> Chunk<'a> {
self.bytecode[idx] = self.bytecode.len() as u8 - idx as u8 + 1;
}
}
Match(scrutinee, clauses) => {
dbg!(&scrutinee);
self.visit(scrutinee.as_ref());
let mut jump_idxes = vec![];
let mut clauses = clauses.iter();
while let Some((MatchClause(pattern, _, body), _)) = clauses.next() {
self.scope_depth += 1;
self.visit(pattern);
self.emit_op(Op::JumpIfNoMatch);
let jnm_jump_idx = self.bytecode.len();
self.bytecode.push(0xff);
self.visit(body);
self.emit_op(Op::Store);
self.scope_depth -= 1;
while let Some(binding) = self.bindings.last() {
if binding.depth > self.scope_depth {
self.emit_op(Op::Pop);
self.bindings.pop();
} else {
break;
}
}
self.emit_op(Op::Jump);
jump_idxes.push(self.bytecode.len());
self.bytecode.push(0xff);
self.bytecode[jnm_jump_idx] =
self.bytecode.len() as u8 - jnm_jump_idx as u8 - 1;
}
self.emit_op(Op::PanicNoMatch);
self.emit_op(Op::Load);
for idx in jump_idxes {
self.bytecode[idx] = self.bytecode.len() as u8 - idx as u8 + 2;
}
}
_ => todo!(),
}
}
@ -406,7 +444,7 @@ impl<'a> Chunk<'a> {
use Op::*;
match op {
Pop | Store | Load | Nil | True | False | MatchNil | MatchTrue | MatchFalse
| MatchWord | ResetMatch | PanicIfNoMatch | GetKey | PanicNoWhen => {
| MatchWord | ResetMatch | PanicIfNoMatch | GetKey | PanicNoWhen | PanicNoMatch => {
println!("{i:04}: {op}")
}
Constant | MatchConstant => {
@ -414,14 +452,11 @@ impl<'a> Chunk<'a> {
let value = &self.constants[*next as usize].show(self);
println!("{i:04}: {:16} {next:04}: {value}", op.to_string());
}
PushBinding | MatchTuple | PushTuple | PushDict | PushList | PushBox => {
PushBinding | MatchTuple | PushTuple | PushDict | PushList | PushBox | Jump
| JumpIfFalse | JumpIfNoMatch => {
let (_, next) = codes.next().unwrap();
println!("{i:04}: {:16} {next:04}", op.to_string());
}
Jump | JumpIfFalse => {
let (_, next) = codes.next().unwrap();
println!("{i:04}: {:16} {next:04}", op.to_string())
}
}
}
}
@ -431,7 +466,7 @@ impl<'a> Chunk<'a> {
use Op::*;
match op {
Pop | Store | Load | Nil | True | False | MatchNil | MatchTrue | MatchFalse
| PanicIfNoMatch | MatchWord | ResetMatch | GetKey | PanicNoWhen => {
| PanicIfNoMatch | MatchWord | ResetMatch | GetKey | PanicNoWhen | PanicNoMatch => {
println!("{i:04}: {op}")
}
Constant | MatchConstant => {
@ -439,14 +474,11 @@ impl<'a> Chunk<'a> {
let value = &self.constants[next as usize].show(self);
println!("{i:04}: {:16} {next:04}: {value}", op.to_string());
}
PushBinding | MatchTuple | PushTuple | PushDict | PushList | PushBox => {
PushBinding | MatchTuple | PushTuple | PushDict | PushList | PushBox | Jump
| JumpIfFalse | JumpIfNoMatch => {
let next = self.bytecode[i + 1];
println!("{i:04}: {:16} {next:04}", op.to_string());
}
Jump | JumpIfFalse => {
let next = self.bytecode[i + 1];
println!("{i:04}: {:16} {next:04}", op.to_string())
}
}
}
}

View File

@ -65,10 +65,15 @@ pub fn run(src: &'static str) {
pub fn main() {
let src = "
let foo = 42
when {
foo -> :two
false -> :four
:else -> :thing
match foo with {
:foo -> {
1
2
x
}
2 -> :two
42 -> :everything
_ -> :something_else
}
";
run(src);

View File

@ -249,7 +249,16 @@ impl<'a> Vm<'a> {
MatchTuple => {
todo!()
}
PanicNoWhen => Err(Panic("no match")),
JumpIfNoMatch => {
let jump_len = self.chunk.bytecode[self.ip + 1] as usize;
if !self.matches {
self.ip += jump_len + 2;
} else {
self.ip += 2;
}
self.interpret()
}
PanicNoWhen | PanicNoMatch => Err(Panic("no match")),
}
}
}