mirror of
https://github.com/uutils/awk.git
synced 2026-06-10 16:15:04 -07:00
interpreter: (in)equality comparisons
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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:?}"),
|
||||
|
||||
Reference in New Issue
Block a user