summaryrefslogtreecommitdiff
path: root/src/eval/ops.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-01-12 18:55:12 +0100
committerLaurenz <laurmaedje@gmail.com>2021-01-12 18:55:12 +0100
commitd2ba1b705ed7a532266294aa100f19423bb07f4d (patch)
tree1f06bf618f2190a3aabc26d69f0fb819e970341c /src/eval/ops.rs
parent105cda0e698fe86266d706f4e3bacc081e65c2aa (diff)
Group and block expressions, unary plus 🧩
Diffstat (limited to 'src/eval/ops.rs')
-rw-r--r--src/eval/ops.rs183
1 files changed, 183 insertions, 0 deletions
diff --git a/src/eval/ops.rs b/src/eval/ops.rs
new file mode 100644
index 00000000..0a273da5
--- /dev/null
+++ b/src/eval/ops.rs
@@ -0,0 +1,183 @@
+use super::*;
+
+/// 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
+ }
+}
+
+/// Compute the negation of a value.
+pub fn neg(ctx: &mut EvalContext, span: Span, value: Value) -> Value {
+ use 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),
+ v => {
+ ctx.diag(error!(span, "cannot negate {}", v.type_name()));
+ Value::Error
+ }
+ }
+}
+
+/// Compute the sum of two values.
+pub fn add(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value {
+ use 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),
+ (Float(a), Float(b)) => Float(a + b),
+ (Angle(a), Angle(b)) => Angle(a + b),
+ (Length(a), Length(b)) => Length(a + b),
+ (Length(a), Relative(b)) => Linear(a + b),
+ (Length(a), Linear(b)) => Linear(a + b),
+ (Relative(a), Length(b)) => Linear(a + b),
+ (Relative(a), Relative(b)) => Relative(a + b),
+ (Relative(a), Linear(b)) => Linear(a + b),
+ (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
+ }
+ }
+}
+
+/// Compute the difference of two values.
+pub fn sub(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value {
+ use 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),
+ (Float(a), Float(b)) => Float(a - b),
+ (Angle(a), Angle(b)) => Angle(a - b),
+ (Length(a), Length(b)) => Length(a - b),
+ (Length(a), Relative(b)) => Linear(a - b),
+ (Length(a), Linear(b)) => Linear(a - b),
+ (Relative(a), Length(b)) => Linear(a - b),
+ (Relative(a), Relative(b)) => Relative(a - b),
+ (Relative(a), Linear(b)) => Linear(a - b),
+ (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
+ }
+ }
+}
+
+/// Compute the product of two values.
+pub fn mul(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value {
+ use 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),
+ (Float(a), Float(b)) => Float(a * b),
+ (Length(a), Int(b)) => Length(a * b as f64),
+ (Length(a), Float(b)) => Length(a * b),
+ (Int(a), Length(b)) => Length(a as f64 * b),
+ (Float(a), Length(b)) => Length(a * b),
+ (Angle(a), Int(b)) => Angle(a * b as f64),
+ (Angle(a), Float(b)) => Angle(a * b),
+ (Int(a), Angle(b)) => Angle(a as f64 * b),
+ (Float(a), Angle(b)) => Angle(a * b),
+ (Relative(a), Int(b)) => Relative(a * b as f64),
+ (Relative(a), Float(b)) => Relative(a * b),
+ (Int(a), Relative(b)) => Relative(a as f64 * b),
+ (Float(a), Relative(b)) => Relative(a * b),
+ (Linear(a), Int(b)) => Linear(a * b as f64),
+ (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
+ }
+ }
+}
+
+/// Compute the quotient of two values.
+pub fn div(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value {
+ use 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),
+ (Float(a), Float(b)) => Float(a / b),
+ (Length(a), Int(b)) => Length(a / b as f64),
+ (Length(a), Float(b)) => Length(a / b),
+ (Angle(a), Int(b)) => Angle(a / b as f64),
+ (Angle(a), Float(b)) => Angle(a / b),
+ (Relative(a), Int(b)) => Relative(a / b as f64),
+ (Relative(a), Float(b)) => Relative(a / b),
+ (Linear(a), Int(b)) => Linear(a / b as f64),
+ (Linear(a), Float(b)) => Linear(a / b),
+
+ (a, b) => {
+ ctx.diag(error!(
+ span,
+ "cannot divide {} by {}",
+ a.type_name(),
+ b.type_name()
+ ));
+ Value::Error
+ }
+ }
+}
+
+/// Concatenate two collections.
+fn concat<T, A>(mut a: T, b: T) -> T
+where
+ T: Extend<A> + IntoIterator<Item = A>,
+{
+ a.extend(b);
+ a
+}