interpreter: (in)equality comparisons

This commit is contained in:
Guillem L. Jara
2026-05-26 08:01:48 +02:00
parent 3b9ce0e689
commit 2006523ae7
2 changed files with 41 additions and 8 deletions
+32 -1
View File
@@ -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<H: std::hash::Hasher>(&self, state: &mut H) {
+9 -7
View File
@@ -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:?}"),