interpreter: ordered boolean comparisons

This commit is contained in:
Guillem L. Jara
2026-05-26 09:01:14 +02:00
parent c0a9ab7e14
commit ca49529a46
3 changed files with 65 additions and 4 deletions
+1 -1
View File
@@ -42,7 +42,6 @@ pub enum OpCode {
Negation,
ToInt,
Negative,
Concat,
// Binary operations
Eq,
@@ -61,6 +60,7 @@ pub enum OpCode {
Divide,
Raise,
Modulo,
Concat,
// Intrinsic operations
LoadUser,
+53
View File
@@ -65,6 +65,10 @@ impl Value<'_> {
}
}
pub fn b2f(b: bool) -> Self {
Self::Float(b as usize as f64)
}
pub fn write_string(&self, f: &mut Vec<u8>) {
match self {
Self::String(s) | Self::Regex(s) => f.extend_from_slice(s),
@@ -171,6 +175,55 @@ impl PartialEq for Value<'_> {
}
}
impl PartialOrd for Value<'_> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
match (self, other) {
// Numeric comparisons
(&Self::Float(lhs), Self::Float(rhs)) => lhs.partial_cmp(rhs),
(&Self::Bool(lhs), Self::Bool(rhs)) => lhs.partial_cmp(rhs),
(&Self::Float(f), &Self::Bool(b)) => f.partial_cmp(&(b as usize as _)),
(&Self::Bool(b), Self::Float(f)) => (b as usize as f64).partial_cmp(f),
// String-based comparisons
(Self::String(lhs) | Self::Regex(lhs), Self::String(rhs) | Self::Regex(rhs)) => {
lhs.as_ref().partial_cmp(rhs)
}
(&Self::Float(f), Self::String(s) | Self::Regex(s)) => {
f.to_string().as_bytes().partial_cmp(s)
}
(Self::String(s) | Self::Regex(s), &Self::Float(f)) => {
s.as_ref().partial_cmp(f.to_string().as_bytes())
}
(&Self::Bool(b), Self::String(s) | Self::Regex(s)) => {
(if b { b"1" } else { b"0" }).as_ref().partial_cmp(s)
}
(Self::String(s) | Self::Regex(s), &Self::Bool(b)) => {
s.as_ref().partial_cmp(if b { b"1" } else { b"0" })
}
(Self::Untyped | Self::Unassigned, Self::String(s) | Self::Regex(s)) => {
b"".as_ref().partial_cmp(s)
}
(Self::String(s) | Self::Regex(s), Self::Untyped | Self::Unassigned) => {
s.as_ref().partial_cmp(b"")
}
(Self::Array(_), _) | (_, Self::Array(_)) => {
panic!("Attempted to use array in scalar context!")
}
(Self::Untyped | Self::Unassigned, Self::Untyped | Self::Unassigned) => {
b"".partial_cmp(b"")
}
// Copyful comparisons
(lhs, rhs) => {
let mut str_buf: Vec<u8> = Vec::new();
str_buf.reserve_exact(lhs.string_size_hint() + rhs.string_size_hint());
lhs.write_string(&mut str_buf);
let midpoint = str_buf.len();
rhs.write_string(&mut str_buf);
str_buf[0..midpoint].partial_cmp(&str_buf[midpoint..])
}
}
}
}
impl Eq for Value<'_> {}
impl Hash for Value<'_> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+11 -3
View File
@@ -130,8 +130,16 @@ impl Interpreter<'_> {
OpCode::Raise => lhs ^ rhs,
OpCode::Modulo => 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::Eq => Value::b2f(lhs == rhs),
OpCode::NEq => Value::b2f(lhs != rhs),
OpCode::Gt => Value::b2f(lhs > rhs),
OpCode::Lt => Value::b2f(lhs < rhs),
OpCode::GtE => Value::b2f(lhs >= rhs),
OpCode::LtE => Value::b2f(lhs <= rhs),
OpCode::And => todo!(),
OpCode::Or => todo!(),
OpCode::Matches => todo!(),
OpCode::MatchesNot => todo!(),
OpCode::Concat => {
let mut buf = StdVec::with_capacity(
lhs.string_size_hint() + rhs.string_size_hint(),
@@ -140,7 +148,7 @@ impl Interpreter<'_> {
rhs.write_string(&mut buf);
Value::String(buf.into())
}
_ => todo!(),
_ => unreachable!(),
};
self.registers.write(dest, val);
}