From 2006523ae7b22f4d3ea0fba5f6cbb0625c549fd9 Mon Sep 17 00:00:00 2001 From: "Guillem L. Jara" <4lon3ly0@tutanota.com> Date: Tue, 26 May 2026 08:01:48 +0200 Subject: [PATCH] interpreter: (in)equality comparisons --- interpreter/src/types.rs | 33 ++++++++++++++++++++++++++++++++- interpreter/src/vm.rs | 16 +++++++++------- 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/interpreter/src/types.rs b/interpreter/src/types.rs index 9243972..38eb4f5 100644 --- a/interpreter/src/types.rs +++ b/interpreter/src/types.rs @@ -10,7 +10,7 @@ use std::{ use ahash::RandomState; use hashbrown::HashMap; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone)] pub enum Value<'a> { Float(f64), String(Cow<'a, [u8]>), @@ -119,6 +119,37 @@ impl<'a> Div for &'_ Value<'a> { } } +impl PartialEq for Value<'_> { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + // Numeric comparisons + (&Self::Float(lhs), &Self::Float(rhs)) => lhs == rhs, + (&Self::Bool(lhs), &Self::Bool(rhs)) => lhs == rhs, + (&Self::Float(f), &Self::Bool(b)) | (&Self::Bool(b), &Self::Float(f)) => b && f == 1., + // String-based comparisons + (Self::String(lhs) | Self::Regex(lhs), Self::String(rhs) | Self::Regex(rhs)) => { + lhs == rhs + } + (&Self::Float(f), Self::String(s) | Self::Regex(s)) + | (Self::String(s) | Self::Regex(s), &Self::Float(f)) => { + f.to_string().as_bytes() == s.as_ref() + } + (&Self::Bool(b), Self::String(s) | Self::Regex(s)) + | (Self::String(s) | Self::Regex(s), &Self::Bool(b)) => { + (if b { b"1" } else { b"0" }) == s.as_ref() + } + // True on empty string value. + (Self::Untyped | Self::Unassigned, Self::String(s) | Self::Regex(s)) + | (Self::String(s) | Self::Regex(s), Self::Untyped | Self::Unassigned) => s.is_empty(), + (Self::Untyped | Self::Unassigned, Self::Untyped | Self::Unassigned) => true, + (Self::Untyped | Self::Unassigned, _) | (_, Self::Untyped | Self::Unassigned) => false, + (Self::Array(_), _) | (_, Self::Array(_)) => { + panic!("Attempted to use array in scalar context!") + } + } + } +} + impl Eq for Value<'_> {} impl Hash for Value<'_> { fn hash(&self, state: &mut H) { diff --git a/interpreter/src/vm.rs b/interpreter/src/vm.rs index ea0059d..b2975d1 100644 --- a/interpreter/src/vm.rs +++ b/interpreter/src/vm.rs @@ -12,7 +12,7 @@ use parser::Identifier; use crate::{ ir::{ - NonLocal, OpCode, Reg, + Label, NonLocal, OpCode, Reg, lower::{Bytecode, Code, ValueContext}, }, types::Value, @@ -127,6 +127,9 @@ impl Interpreter<'_> { OpCode::Subtract => lhs - rhs, OpCode::Multiply => lhs * rhs, OpCode::Divide => lhs / rhs, + // Float values on boolean cmps are intentional. + OpCode::Eq => Value::Float((lhs == rhs) as usize as _), + OpCode::NEq => Value::Float((lhs != rhs) as usize as _), OpCode::Concat => { let mut buf = StdVec::with_capacity( lhs.string_size_hint() + rhs.string_size_hint(), @@ -154,18 +157,17 @@ impl Interpreter<'_> { } _ => todo!(), }, - ix if let Some((cond, true_to, false_to)) = ix.get_branch() => { + ix if let Some((cond, Label(true_to), Label(false_to))) = ix.get_branch() => { let label = if self.registers.get(*cond).to_bool() { - true_to.0 + *true_to } else { - false_to.0 + *false_to }; self.program_counter = label as _; - continue; } - ix if let Some(label) = ix.get_jump() => { - self.program_counter = label.0 as _; + ix if let Some(&Label(label)) = ix.get_jump() => { + self.program_counter = label as _; continue; } ix => todo!("{ix:?}"),