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, PushBox,
GetKey, GetKey,
PanicNoWhen, PanicNoWhen,
JumpIfNoMatch,
PanicNoMatch,
} }
impl std::fmt::Display for Op { impl std::fmt::Display for Op {
@ -61,6 +63,8 @@ impl std::fmt::Display for Op {
PushBox => "push_box", PushBox => "push_box",
GetKey => "get_key", GetKey => "get_key",
PanicNoWhen => "panic_no_when", PanicNoWhen => "panic_no_when",
JumpIfNoMatch => "jump_if_no_match",
PanicNoMatch => "panic_no_match",
}; };
write!(f, "{rep}") write!(f, "{rep}")
} }
@ -393,6 +397,40 @@ impl<'a> Chunk<'a> {
self.bytecode[idx] = self.bytecode.len() as u8 - idx as u8 + 1; 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!(), _ => todo!(),
} }
} }
@ -406,7 +444,7 @@ impl<'a> Chunk<'a> {
use Op::*; use Op::*;
match op { match op {
Pop | Store | Load | Nil | True | False | MatchNil | MatchTrue | MatchFalse Pop | Store | Load | Nil | True | False | MatchNil | MatchTrue | MatchFalse
| MatchWord | ResetMatch | PanicIfNoMatch | GetKey | PanicNoWhen => { | MatchWord | ResetMatch | PanicIfNoMatch | GetKey | PanicNoWhen | PanicNoMatch => {
println!("{i:04}: {op}") println!("{i:04}: {op}")
} }
Constant | MatchConstant => { Constant | MatchConstant => {
@ -414,14 +452,11 @@ impl<'a> Chunk<'a> {
let value = &self.constants[*next as usize].show(self); let value = &self.constants[*next as usize].show(self);
println!("{i:04}: {:16} {next:04}: {value}", op.to_string()); 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(); let (_, next) = codes.next().unwrap();
println!("{i:04}: {:16} {next:04}", op.to_string()); 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::*; use Op::*;
match op { match op {
Pop | Store | Load | Nil | True | False | MatchNil | MatchTrue | MatchFalse Pop | Store | Load | Nil | True | False | MatchNil | MatchTrue | MatchFalse
| PanicIfNoMatch | MatchWord | ResetMatch | GetKey | PanicNoWhen => { | PanicIfNoMatch | MatchWord | ResetMatch | GetKey | PanicNoWhen | PanicNoMatch => {
println!("{i:04}: {op}") println!("{i:04}: {op}")
} }
Constant | MatchConstant => { Constant | MatchConstant => {
@ -439,14 +474,11 @@ impl<'a> Chunk<'a> {
let value = &self.constants[next as usize].show(self); let value = &self.constants[next as usize].show(self);
println!("{i:04}: {:16} {next:04}: {value}", op.to_string()); 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]; let next = self.bytecode[i + 1];
println!("{i:04}: {:16} {next:04}", op.to_string()); 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() { pub fn main() {
let src = " let src = "
let foo = 42 let foo = 42
when { match foo with {
foo -> :two :foo -> {
false -> :four 1
:else -> :thing 2
x
}
2 -> :two
42 -> :everything
_ -> :something_else
} }
"; ";
run(src); run(src);

View File

@ -249,7 +249,16 @@ impl<'a> Vm<'a> {
MatchTuple => { MatchTuple => {
todo!() 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")),
} }
} }
} }