feat!(semantics): Use function for evaluating numeric expressions
This commit is contained in:
parent
2e574c6009
commit
c666498ac0
2 changed files with 50 additions and 92 deletions
|
|
@ -6,6 +6,7 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
argus-core = { version = "0.1.0", path = "../argus-core" }
|
argus-core = { version = "0.1.0", path = "../argus-core" }
|
||||||
itertools = "0.10.5"
|
itertools = "0.10.5"
|
||||||
|
num-traits = "0.2.15"
|
||||||
paste = "1.0.12"
|
paste = "1.0.12"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
||||||
|
|
@ -1,102 +1,59 @@
|
||||||
use argus_core::expr::NumExpr;
|
use argus_core::prelude::*;
|
||||||
use argus_core::signals::{AnySignal, ConstantSignal};
|
use argus_core::signals::traits::{SignalAbs, TrySignalCast};
|
||||||
|
use num_traits::{Num, NumCast};
|
||||||
|
|
||||||
use crate::Trace;
|
use crate::Trace;
|
||||||
|
|
||||||
macro_rules! signal_num_op_impl {
|
pub fn eval_num_expr<T>(root: &NumExpr, trace: &impl Trace) -> ArgusResult<Signal<T>>
|
||||||
// Unary numeric opeartions
|
where
|
||||||
($op:ident, $signal:ident, [$( $type:ident ),*]) => {
|
T: Num + NumCast,
|
||||||
paste::paste! {
|
Signal<i64>: TrySignalCast<Signal<T>>,
|
||||||
{
|
Signal<u64>: TrySignalCast<Signal<T>>,
|
||||||
use argus_core::prelude::*;
|
Signal<f64>: TrySignalCast<Signal<T>>,
|
||||||
use AnySignal::*;
|
Signal<T>: std::ops::Neg<Output = Signal<T>>,
|
||||||
match $signal {
|
Signal<T>: std::ops::Add<Signal<T>, Output = Signal<T>>,
|
||||||
$(
|
Signal<T>: std::ops::Sub<Signal<T>, Output = Signal<T>>,
|
||||||
[< $type >](signal) => AnySignal::from(signal.$op()),
|
Signal<T>: std::ops::Mul<Signal<T>, Output = Signal<T>>,
|
||||||
[<Const $type >](signal) => AnySignal::from(signal.$op()),
|
Signal<T>: std::ops::Div<Signal<T>, Output = Signal<T>>,
|
||||||
)*
|
Signal<T>: SignalAbs,
|
||||||
_ => panic!("cannot perform unary operation ({})", stringify!($op)),
|
{
|
||||||
}
|
match root {
|
||||||
|
NumExpr::IntLit(val) => Signal::constant(*val).try_cast(),
|
||||||
|
NumExpr::UIntLit(val) => Signal::constant(*val).try_cast(),
|
||||||
|
NumExpr::FloatLit(val) => Signal::constant(*val).try_cast(),
|
||||||
|
NumExpr::IntVar { name } => trace.get::<i64>(name.as_str()).unwrap().try_cast(),
|
||||||
|
NumExpr::UIntVar { name } => trace.get::<u64>(name.as_str()).unwrap().try_cast(),
|
||||||
|
NumExpr::FloatVar { name } => trace.get::<f64>(name.as_str()).unwrap().try_cast(),
|
||||||
|
NumExpr::Neg { arg } => eval_num_expr(arg, trace).map(|sig| -sig),
|
||||||
|
NumExpr::Add { args } => {
|
||||||
|
let mut ret: Signal<T> = Signal::constant(0i64).try_cast()?;
|
||||||
|
for arg in args.iter() {
|
||||||
|
let arg = eval_num_expr(arg, trace)?;
|
||||||
|
ret = ret + arg;
|
||||||
}
|
}
|
||||||
|
Ok(ret)
|
||||||
}
|
}
|
||||||
};
|
NumExpr::Sub { lhs, rhs } => {
|
||||||
|
let lhs = eval_num_expr(lhs, trace)?;
|
||||||
($op:ident, $lhs:ident, $rhs:ident, [$( $type:ident ),*]) => {
|
let rhs = eval_num_expr(rhs, trace)?;
|
||||||
paste::paste!{
|
Ok(lhs - rhs)
|
||||||
{
|
|
||||||
use argus_core::prelude::*;
|
|
||||||
use AnySignal::*;
|
|
||||||
match ($lhs, $rhs) {
|
|
||||||
(Bool(_), _) | (ConstBool(_), _) | (_, Bool(_)) | (_, ConstBool(_)) => panic!("cannot perform numeric operation {} for boolean arguments", stringify!($op)),
|
|
||||||
$(
|
|
||||||
([<$type >](lhs), [< $type >](rhs)) => AnySignal::from(lhs.$op(&rhs)),
|
|
||||||
([<$type >](lhs), [< Const $type >](rhs)) => AnySignal::from(lhs.$op(&rhs)),
|
|
||||||
([<Const $type >](lhs), [< $type >](rhs)) => AnySignal::from(lhs.$op(&rhs)),
|
|
||||||
([<Const $type >](lhs), [< Const $type >](rhs)) => AnySignal::from(lhs.$op(&rhs)),
|
|
||||||
)*
|
|
||||||
_ => panic!("mismatched argument types for {} operation", stringify!($op)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
NumExpr::Mul { args } => {
|
||||||
|
let mut ret: Signal<T> = Signal::constant(1i64).try_cast()?;
|
||||||
// Binary numeric opeartions
|
for arg in args.iter() {
|
||||||
($op:ident, $lhs:ident, $rhs:ident) => {
|
let arg = eval_num_expr(arg, trace)?;
|
||||||
signal_num_op_impl!(
|
ret = ret * arg;
|
||||||
$op, $lhs, $rhs,
|
|
||||||
[Int, UInt, Float]
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) use signal_num_op_impl;
|
|
||||||
|
|
||||||
/// Helper struct to evaluate a [`NumExpr`] given a trace.
|
|
||||||
pub struct NumExprEval;
|
|
||||||
|
|
||||||
impl NumExprEval {
|
|
||||||
pub fn eval(root: &NumExpr, trace: &impl Trace) -> AnySignal {
|
|
||||||
use core::ops::{Add, Div, Mul, Neg, Sub};
|
|
||||||
|
|
||||||
use argus_core::signals::traits::SignalAbs;
|
|
||||||
match root {
|
|
||||||
NumExpr::IntLit(val) => ConstantSignal::new(*val).into(),
|
|
||||||
NumExpr::UIntLit(val) => ConstantSignal::new(*val).into(),
|
|
||||||
NumExpr::FloatLit(val) => ConstantSignal::new(*val).into(),
|
|
||||||
NumExpr::IntVar { name } | NumExpr::UIntVar { name } | NumExpr::FloatVar { name } => {
|
|
||||||
// TODO(anand): Type check!
|
|
||||||
trace.get(name.as_str()).cloned().unwrap()
|
|
||||||
}
|
|
||||||
NumExpr::Neg { arg } => {
|
|
||||||
let arg_sig = Self::eval(arg, trace);
|
|
||||||
signal_num_op_impl!(neg, arg_sig, [Int, Float])
|
|
||||||
}
|
|
||||||
NumExpr::Add { args } => {
|
|
||||||
let args_signals = args.iter().map(|arg| Self::eval(arg, trace));
|
|
||||||
args_signals
|
|
||||||
.reduce(|acc, arg| signal_num_op_impl!(add, acc, arg))
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
NumExpr::Sub { lhs, rhs } => {
|
|
||||||
let lhs = Self::eval(lhs, trace);
|
|
||||||
let rhs = Self::eval(rhs, trace);
|
|
||||||
signal_num_op_impl!(sub, lhs, rhs)
|
|
||||||
}
|
|
||||||
NumExpr::Mul { args } => {
|
|
||||||
let args_signals = args.iter().map(|arg| Self::eval(arg, trace));
|
|
||||||
args_signals
|
|
||||||
.reduce(|acc, arg| signal_num_op_impl!(mul, acc, arg))
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
NumExpr::Div { dividend, divisor } => {
|
|
||||||
let dividend = Self::eval(dividend, trace);
|
|
||||||
let divisor = Self::eval(divisor, trace);
|
|
||||||
signal_num_op_impl!(div, dividend, divisor)
|
|
||||||
}
|
|
||||||
NumExpr::Abs { arg } => {
|
|
||||||
let arg = Self::eval(arg, trace);
|
|
||||||
signal_num_op_impl!(abs, arg, [Int, UInt, Float])
|
|
||||||
}
|
}
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
NumExpr::Div { dividend, divisor } => {
|
||||||
|
let dividend = eval_num_expr(dividend, trace)?;
|
||||||
|
let divisor = eval_num_expr(divisor, trace)?;
|
||||||
|
Ok(dividend / divisor)
|
||||||
|
}
|
||||||
|
NumExpr::Abs { arg } => {
|
||||||
|
let arg = eval_num_expr(arg, trace)?;
|
||||||
|
Ok(arg.abs())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue