feat(vm): basic comparison operators

This commit is contained in:
Alain Zscheile 2022-09-28 02:08:00 +02:00
parent 7602e9f7b9
commit b67f42b773
3 changed files with 26 additions and 18 deletions

View file

@ -50,6 +50,10 @@ impl Sealed for MathUnOp {}
pub enum MathBinOp {
Concat = 0x2e, /* . */
// comparison operations
Lt = 0x3c, /* < */
Eq = 0x3d, /* = */
// bit operations
And = 0x26, /* & */
Or = 0x7c, /* | */

View file

@ -50,6 +50,8 @@ pub enum Instr<'a> {
/// basic math operations (on integers and atoms)
DoMath1(MathUnOp),
/// binary math operations, stack top is like: `... lhs rhs $`
DoMath2(MathBinOp),
}

View file

@ -120,15 +120,17 @@ fn verify_jumptarget_explicit(
Ok(())
}
fn u128_binmath(a: u128, b: u128, mbo: consts::MathBinOp) -> Result<u128, Error> {
fn u128_binmath(a: u128, b: u128, mbo: consts::MathBinOp) -> Result<StackEntValue, Error> {
use consts::MathBinOp as B;
Ok(match mbo {
Ok(StackEntValue::Atom(Atom::from(match mbo {
B::Concat => {
return Err(Error::StackedInvalidType {
expected: "bytes,bytes",
got: "[int|atom, int|atom]".to_string(),
})
}
B::Lt => return Ok(StackEntValue::Int(if a < b { 1 } else { 0 })),
B::Eq => return Ok(StackEntValue::Int(if a < b { 1 } else { 0 })),
B::And => a & b,
B::Or => a | b,
B::Xor => a ^ b,
@ -143,7 +145,7 @@ fn u128_binmath(a: u128, b: u128, mbo: consts::MathBinOp) -> Result<u128, Error>
Some(x) => x,
None => return Err(Error::DivisionByZero),
},
})
})))
}
impl Process {
@ -341,6 +343,8 @@ impl Process {
self.stack.push(match (a, b) {
(V::Int(a), V::Int(b)) => match mbo {
B::Concat => V::Atom(Atom::from((a, b))),
B::Lt => V::Int(if a < b { 1 } else { 0 }),
B::Eq => V::Int(if a == b { 1 } else { 0 }),
B::And => V::Int(a & b),
B::Or => V::Int(a | b),
B::Xor => V::Int(a ^ b),
@ -359,21 +363,18 @@ impl Process {
}),
},
(V::Atom(a), V::Atom(b)) => {
V::Atom(Atom::from(u128_binmath(u128::from(a), u128::from(b), mbo)?))
u128_binmath(u128::from(a), u128::from(b), mbo)?
}
(V::Int(a), V::Atom(b)) => {
V::Atom(Atom::from(u128_binmath(u128::from(a), u128::from(b), mbo)?))
}
(V::Atom(a), V::Int(b)) => {
V::Atom(Atom::from(u128_binmath(u128::from(a), u128::from(b), mbo)?))
}
(V::Bytes(a), V::Bytes(b)) => V::Bytes(match mbo {
(V::Int(a), V::Atom(b)) => u128_binmath(u128::from(a), u128::from(b), mbo)?,
(V::Atom(a), V::Int(b)) => u128_binmath(u128::from(a), u128::from(b), mbo)?,
(V::Bytes(a), V::Bytes(b)) => match mbo {
B::Concat => {
let mut x = Vec::with_capacity(a.len() + b.len());
x.extend_from_slice(&a);
x.extend_from_slice(&b);
x
V::Bytes(x)
}
B::Eq => V::Int(if a == b { 1 } else { 0 }),
B::And => {
let mut x: Vec<_> =
a.iter().zip(b.iter()).map(|(w, v)| w & v).collect();
@ -381,7 +382,7 @@ impl Process {
x.extend_from_slice(
&(if a.len() < b.len() { b } else { a })[minp..],
);
x
V::Bytes(x)
}
B::Or => {
let mut x: Vec<_> =
@ -390,7 +391,7 @@ impl Process {
x.extend_from_slice(
&(if a.len() < b.len() { b } else { a })[minp..],
);
x
V::Bytes(x)
}
B::Xor => {
let mut x: Vec<_> =
@ -399,7 +400,7 @@ impl Process {
x.extend_from_slice(
&(if a.len() < b.len() { b } else { a })[minp..],
);
x
V::Bytes(x)
}
_ => {
return Err(Error::StackedInvalidType {
@ -407,7 +408,8 @@ impl Process {
got: "[bytes, bytes]".to_string(),
})
}
}),
},
_ if mbo == B::Eq => V::Int(0),
(a, b) => {
return Err(Error::StackedInvalidType {
expected: "[int|atom, int|atom] | [bytes,bytes]",
@ -431,7 +433,7 @@ mod tests {
}
proptest::proptest! {
#![proptest_config(proptest::prelude::ProptestConfig::with_cases(4096))]
#![proptest_config(proptest::prelude::ProptestConfig::with_cases(8192))]
#[test]
fn doesnt_crash(inp in proptest::collection::vec(0..=u8::MAX, 0..1024)) {
@ -449,7 +451,7 @@ mod tests {
pos: 0,
},
};
let _ = futures_lite::future::block_on(p.run(Some(&mut 1024)));
let _ = futures_lite::future::block_on(p.run(Some(&mut 2048)));
}
}
}