diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-01-22 17:16:42 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-01-22 17:16:42 +0100 |
| commit | ac788f2082711161ec8208eede04d9a2bae02241 (patch) | |
| tree | b139e41d327af906163c0b177d402b855c04507e /src/eval/ops.rs | |
| parent | 0de4f3ed7bb20a94fd58f93b0793d3b5a8e13972 (diff) | |
Many more expressions 🥗
Boolean, equality, comparison and assignment expression parsing and evaluation.
Diffstat (limited to 'src/eval/ops.rs')
| -rw-r--r-- | src/eval/ops.rs | 177 |
1 files changed, 103 insertions, 74 deletions
diff --git a/src/eval/ops.rs b/src/eval/ops.rs index 0a273da5..939445f0 100644 --- a/src/eval/ops.rs +++ b/src/eval/ops.rs @@ -1,22 +1,21 @@ use super::*; +use Value::*; -/// Apply plus operator to a value. -pub fn pos(ctx: &mut EvalContext, span: Span, value: Value) -> Value { - if value.is_numeric() { - value - } else { - ctx.diag(error!( - span, - "cannot apply plus operator to {}", - value.type_name() - )); - Value::Error +/// Apply the plus operator to a value. +pub fn pos(value: Value) -> Value { + match value { + Int(v) => Int(v), + Float(v) => Float(v), + Length(v) => Length(v), + Angle(v) => Angle(v), + Relative(v) => Relative(v), + Linear(v) => Linear(v), + _ => Error, } } /// Compute the negation of a value. -pub fn neg(ctx: &mut EvalContext, span: Span, value: Value) -> Value { - use Value::*; +pub fn neg(value: Value) -> Value { match value { Int(v) => Int(-v), Float(v) => Float(-v), @@ -24,18 +23,13 @@ pub fn neg(ctx: &mut EvalContext, span: Span, value: Value) -> Value { Angle(v) => Angle(-v), Relative(v) => Relative(-v), Linear(v) => Linear(-v), - v => { - ctx.diag(error!(span, "cannot negate {}", v.type_name())); - Value::Error - } + _ => Error, } } /// Compute the sum of two values. -pub fn add(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value { - use Value::*; +pub fn add(lhs: Value, rhs: Value) -> Value { match (lhs, rhs) { - // Numeric types to themselves. (Int(a), Int(b)) => Int(a + b), (Int(a), Float(b)) => Float(a as f64 + b), (Float(a), Int(b)) => Float(a + b as f64), @@ -50,30 +44,17 @@ pub fn add(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value { (Linear(a), Length(b)) => Linear(a + b), (Linear(a), Relative(b)) => Linear(a + b), (Linear(a), Linear(b)) => Linear(a + b), - - // Complex data types to themselves. (Str(a), Str(b)) => Str(a + &b), (Array(a), Array(b)) => Array(concat(a, b)), (Dict(a), Dict(b)) => Dict(concat(a, b)), (Template(a), Template(b)) => Template(concat(a, b)), - - (a, b) => { - ctx.diag(error!( - span, - "cannot add {} and {}", - a.type_name(), - b.type_name() - )); - Value::Error - } + _ => Error, } } /// Compute the difference of two values. -pub fn sub(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value { - use Value::*; +pub fn sub(lhs: Value, rhs: Value) -> Value { match (lhs, rhs) { - // Numbers from themselves. (Int(a), Int(b)) => Int(a - b), (Int(a), Float(b)) => Float(a as f64 - b), (Float(a), Int(b)) => Float(a - b as f64), @@ -88,24 +69,13 @@ pub fn sub(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value { (Linear(a), Length(b)) => Linear(a - b), (Linear(a), Relative(b)) => Linear(a - b), (Linear(a), Linear(b)) => Linear(a - b), - - (a, b) => { - ctx.diag(error!( - span, - "cannot subtract {1} from {0}", - a.type_name(), - b.type_name() - )); - Value::Error - } + _ => Error, } } /// Compute the product of two values. -pub fn mul(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value { - use Value::*; +pub fn mul(lhs: Value, rhs: Value) -> Value { match (lhs, rhs) { - // Numeric types with numbers. (Int(a), Int(b)) => Int(a * b), (Int(a), Float(b)) => Float(a as f64 * b), (Float(a), Int(b)) => Float(a * b as f64), @@ -126,28 +96,13 @@ pub fn mul(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value { (Linear(a), Float(b)) => Linear(a * b), (Int(a), Linear(b)) => Linear(a as f64 * b), (Float(a), Linear(b)) => Linear(a * b), - - // Integers with strings. - (Int(a), Str(b)) => Str(b.repeat(0.max(a) as usize)), - (Str(a), Int(b)) => Str(a.repeat(0.max(b) as usize)), - - (a, b) => { - ctx.diag(error!( - span, - "cannot multiply {} with {}", - a.type_name(), - b.type_name() - )); - Value::Error - } + _ => Error, } } /// Compute the quotient of two values. -pub fn div(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value { - use Value::*; +pub fn div(lhs: Value, rhs: Value) -> Value { match (lhs, rhs) { - // Numeric types by numbers. (Int(a), Int(b)) => Float(a as f64 / b as f64), (Int(a), Float(b)) => Float(a as f64 / b), (Float(a), Int(b)) => Float(a / b as f64), @@ -160,19 +115,93 @@ pub fn div(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value { (Relative(a), Float(b)) => Relative(a / b), (Linear(a), Int(b)) => Linear(a / b as f64), (Linear(a), Float(b)) => Linear(a / b), + _ => Error, + } +} - (a, b) => { - ctx.diag(error!( - span, - "cannot divide {} by {}", - a.type_name(), - b.type_name() - )); - Value::Error - } +/// Compute the logical "not" of a value. +pub fn not(value: Value) -> Value { + match value { + Bool(b) => Bool(!b), + _ => Error, } } +/// Compute the logical "and" of two values. +pub fn and(lhs: Value, rhs: Value) -> Value { + match (lhs, rhs) { + (Bool(a), Bool(b)) => Bool(a && b), + _ => Error, + } +} + +/// Compute the logical "or" of two values. +pub fn or(lhs: Value, rhs: Value) -> Value { + match (lhs, rhs) { + (Bool(a), Bool(b)) => Bool(a || b), + _ => Error, + } +} + +/// Compute whether two values are equal. +pub fn eq(lhs: Value, rhs: Value) -> Value { + Bool(value_eq(&lhs, &rhs)) +} + +/// Compute whether two values are equal. +pub fn neq(lhs: Value, rhs: Value) -> Value { + Bool(!value_eq(&lhs, &rhs)) +} + +/// Recursively compute whether two values are equal. +fn value_eq(lhs: &Value, rhs: &Value) -> bool { + match (lhs, rhs) { + (&Int(a), &Float(b)) => a as f64 == b, + (&Float(a), &Int(b)) => a == b as f64, + (&Length(a), &Linear(b)) => a == b.abs && b.rel.is_zero(), + (&Relative(a), &Linear(b)) => a == b.rel && b.abs.is_zero(), + (&Linear(a), &Length(b)) => a.abs == b && a.rel.is_zero(), + (&Linear(a), &Relative(b)) => a.rel == b && a.abs.is_zero(), + (Array(a), Array(b)) => array_eq(a, b), + (Dict(a), Dict(b)) => dict_eq(a, b), + (Template(a), Template(b)) => Span::without_cmp(|| a == b), + (a, b) => a == b, + } +} + +/// Compute whether two arrays are equal. +fn array_eq(a: &ValueArray, b: &ValueArray) -> bool { + a.len() == b.len() && a.iter().zip(b).all(|(x, y)| value_eq(x, y)) +} + +/// Compute whether two dictionaries are equal. +fn dict_eq(a: &ValueDict, b: &ValueDict) -> bool { + a.len() == b.len() + && a.iter().all(|(k, x)| b.get(k).map_or(false, |y| value_eq(x, y))) +} + +macro_rules! comparison { + ($name:ident, $op:tt) => { + /// Compute how a value compares with another value. + pub fn $name(lhs: Value, rhs: Value) -> Value { + match (lhs, rhs) { + (Int(a), Int(b)) => Bool(a $op b), + (Int(a), Float(b)) => Bool((a as f64) $op b), + (Float(a), Int(b)) => Bool(a $op b as f64), + (Float(a), Float(b)) => Bool(a $op b), + (Angle(a), Angle(b)) => Bool(a $op b), + (Length(a), Length(b)) => Bool(a $op b), + _ => Error, + } + } + }; +} + +comparison!(lt, <); +comparison!(leq, <=); +comparison!(gt, >); +comparison!(geq, >=); + /// Concatenate two collections. fn concat<T, A>(mut a: T, b: T) -> T where |
