From 01ce043379cf11f5ed62345e5385efcf6ace5289 Mon Sep 17 00:00:00 2001 From: Scott Richmond Date: Wed, 4 Jun 2025 18:51:07 -0400 Subject: [PATCH] guards work in match forms --- src/compiler.rs | 77 +++++++++++++++++++------------------------------ src/main.rs | 8 ++--- 2 files changed, 32 insertions(+), 53 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 465eca9..1737b95 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -5,6 +5,7 @@ use crate::value::*; use chumsky::prelude::SimpleSpan; use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::FromPrimitive; +use std::borrow::Borrow; use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; @@ -911,61 +912,41 @@ impl<'a> Compiler<'a> { let mut jump_idxes = vec![]; let mut clauses = clauses.iter(); while let Some((MatchClause(pattern, guard, body), _)) = clauses.next() { + let mut no_match_jumps = vec![]; self.scope_depth += 1; self.match_depth = 0; self.visit(pattern); self.emit_op(Op::JumpIfNoMatch); - let jnm_jump_idx = self.len(); + no_match_jumps.push(self.len()); self.emit_byte(0xff); - // conditional compilation of guards - // hard to DRY out - match guard.as_ref() { - Some(_) => todo!(), - // Some(expr) => { - // self.visit(expr); - // self.emit_op(Op::JumpIfFalse); - // let jif_idx = self.len(); - // self.emit_byte(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.pop(); - // // self.emit_op(Op::Pop); - // self.bindings.pop(); - // } else { - // break; - // } - // } - // self.emit_op(Op::Jump); - // jump_idxes.push(self.len()); - // self.emit_byte(0xff); - // self.chunk.bytecode[jnm_jump_idx] = - // self.len() as u8 - jnm_jump_idx as u8 - 1; - // self.chunk.bytecode[jif_idx] = self.len() as u8 - jif_idx as u8 - 1; - // } - None => { - 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.bindings.pop(); - } else { - break; - } - } - while self.stack_depth > stack_depth { - self.pop(); - } - self.emit_op(Op::Jump); - jump_idxes.push(self.len()); - self.emit_byte(0xff); - self.chunk.bytecode[jnm_jump_idx] = - self.len() as u8 - jnm_jump_idx as u8 - 1; + if guard.is_some() { + let guard_expr: &'static Spanned = + Box::leak(Box::new(guard.clone().unwrap())); + self.visit(guard_expr); + self.emit_op(Op::JumpIfFalse); + no_match_jumps.push(self.len()); + self.emit_byte(0xff); + self.stack_depth -= 1; + } + 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.bindings.pop(); + } else { + break; } } + while self.stack_depth > stack_depth { + self.pop(); + } + self.emit_op(Op::Jump); + jump_idxes.push(self.len()); + self.emit_byte(0xff); + for idx in no_match_jumps { + self.chunk.bytecode[idx] = self.len() as u8 - idx as u8 - 1; + } } self.emit_op(Op::PanicNoMatch); for idx in jump_idxes { diff --git a/src/main.rs b/src/main.rs index 6f431b1..23fe9b3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -76,12 +76,10 @@ pub fn run(src: &'static str) { pub fn main() { env::set_var("RUST_BACKTRACE", "1"); let src = " -let bar = 42 -let foo = { - let (1, 2, 3) = (1, 2, 3) +match :foo with { + :foo if eq? (1, 2) -> :no + x if eq? (x, :foo) -> :yes } - -foo "; run(src); }