From be23ee6c4409333243da26c87bd26bdfdf89c1c9 Mon Sep 17 00:00:00 2001 From: Scott Richmond Date: Sun, 22 Dec 2024 19:33:59 -0500 Subject: [PATCH] get simple match forms done --- src/compiler.rs | 56 ++++++++++++++++++++++++++++++++++++++----------- src/main.rs | 13 ++++++++---- src/vm.rs | 11 +++++++++- 3 files changed, 63 insertions(+), 17 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 86208cc..d5cf245 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -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()) - } } } } diff --git a/src/main.rs b/src/main.rs index 433f171..87fb76a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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); diff --git a/src/vm.rs b/src/vm.rs index 3f28833..f4dfe35 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -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")), } } }