diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-01-12 18:55:12 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-01-12 18:55:12 +0100 |
| commit | d2ba1b705ed7a532266294aa100f19423bb07f4d (patch) | |
| tree | 1f06bf618f2190a3aabc26d69f0fb819e970341c /src/eval | |
| parent | 105cda0e698fe86266d706f4e3bacc081e65c2aa (diff) | |
Group and block expressions, unary plus 🧩
Diffstat (limited to 'src/eval')
| -rw-r--r-- | src/eval/mod.rs | 200 | ||||
| -rw-r--r-- | src/eval/ops.rs | 183 | ||||
| -rw-r--r-- | src/eval/value.rs | 24 |
3 files changed, 215 insertions, 192 deletions
diff --git a/src/eval/mod.rs b/src/eval/mod.rs index efa74596..32a7d6ba 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -4,6 +4,7 @@ mod value; mod call; mod context; +mod ops; mod scope; mod state; @@ -45,17 +46,6 @@ pub trait Eval { fn eval(self, ctx: &mut EvalContext) -> Self::Output; } -impl<'a, T> Eval for &'a Box<Spanned<T>> -where - Spanned<&'a T>: Eval, -{ - type Output = <Spanned<&'a T> as Eval>::Output; - - fn eval(self, ctx: &mut EvalContext) -> Self::Output { - (**self).as_ref().eval(ctx) - } -} - impl Eval for &[Spanned<Node>] { type Output = (); @@ -171,6 +161,8 @@ impl Eval for Spanned<&Expr> { Expr::Array(v) => Value::Array(v.with_span(self.span).eval(ctx)), Expr::Dict(v) => Value::Dict(v.with_span(self.span).eval(ctx)), Expr::Template(v) => Value::Template(v.clone()), + Expr::Group(v) => v.as_ref().with_span(self.span).eval(ctx), + Expr::Block(v) => v.as_ref().with_span(self.span).eval(ctx), } } } @@ -179,7 +171,7 @@ impl Eval for Spanned<&ExprUnary> { type Output = Value; fn eval(self, ctx: &mut EvalContext) -> Self::Output { - let value = self.v.expr.eval(ctx); + let value = (*self.v.expr).as_ref().eval(ctx); if let Value::Error = value { return Value::Error; @@ -187,7 +179,8 @@ impl Eval for Spanned<&ExprUnary> { let span = self.v.op.span.join(self.v.expr.span); match self.v.op.v { - UnOp::Neg => neg(ctx, span, value), + UnOp::Pos => ops::pos(ctx, span, value), + UnOp::Neg => ops::neg(ctx, span, value), } } } @@ -196,8 +189,8 @@ impl Eval for Spanned<&ExprBinary> { type Output = Value; fn eval(self, ctx: &mut EvalContext) -> Self::Output { - let lhs = self.v.lhs.eval(ctx); - let rhs = self.v.rhs.eval(ctx); + let lhs = (*self.v.lhs).as_ref().eval(ctx); + let rhs = (*self.v.rhs).as_ref().eval(ctx); if lhs == Value::Error || rhs == Value::Error { return Value::Error; @@ -205,10 +198,10 @@ impl Eval for Spanned<&ExprBinary> { let span = self.v.lhs.span.join(self.v.rhs.span); match self.v.op.v { - BinOp::Add => add(ctx, span, lhs, rhs), - BinOp::Sub => sub(ctx, span, lhs, rhs), - BinOp::Mul => mul(ctx, span, lhs, rhs), - BinOp::Div => div(ctx, span, lhs, rhs), + BinOp::Add => ops::add(ctx, span, lhs, rhs), + BinOp::Sub => ops::sub(ctx, span, lhs, rhs), + BinOp::Mul => ops::mul(ctx, span, lhs, rhs), + BinOp::Div => ops::div(ctx, span, lhs, rhs), } } } @@ -231,172 +224,3 @@ impl Eval for Spanned<&ExprDict> { .collect() } } - -/// Compute the negation of a value. -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), - 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. -fn add(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value { - use Value::*; - match (lhs, rhs) { - // Numbers 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), - - // Lengths, relatives and linears to themselves. - (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. -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), - - // Lengths, relatives and linears from themselves. - (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. -fn mul(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value { - use Value::*; - match (lhs, rhs) { - // Numbers with 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), - - // Lengths, relatives and linears with numbers. - (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), - (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. -fn div(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value { - use Value::*; - match (lhs, rhs) { - // Numbers by themselves. - (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), - - // Lengths by numbers. - (Length(a), Int(b)) => Length(a / b as f64), - (Length(a), Float(b)) => Length(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 -} 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 +} diff --git a/src/eval/value.rs b/src/eval/value.rs index d3b2688b..13548c87 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -8,7 +8,7 @@ use super::{Args, Eval, EvalContext}; use crate::color::Color; use crate::geom::{Angle, Length, Linear, Relative}; use crate::pretty::{pretty, Pretty, Printer}; -use crate::syntax::{pretty_template_expr, Spanned, Tree, WithSpan}; +use crate::syntax::{Spanned, Tree, WithSpan}; /// A computational value. #[derive(Debug, Clone, PartialEq)] @@ -77,6 +77,18 @@ impl Value { Self::Error => "error", } } + + /// Whether the value is numeric. + pub fn is_numeric(&self) -> bool { + matches!(self, + Value::Int(_) + | Value::Float(_) + | Value::Length(_) + | Value::Angle(_) + | Value::Relative(_) + | Value::Linear(_) + ) + } } impl Eval for &Value { @@ -112,9 +124,13 @@ impl Pretty for Value { Value::Linear(v) => write!(p, "{}", v).unwrap(), Value::Color(v) => write!(p, "{}", v).unwrap(), Value::Str(v) => write!(p, "{:?}", v).unwrap(), - Value::Array(array) => array.pretty(p), - Value::Dict(dict) => dict.pretty(p), - Value::Template(template) => pretty_template_expr(template, p), + Value::Array(v) => v.pretty(p), + Value::Dict(v) => v.pretty(p), + Value::Template(v) => { + p.push_str("["); + v.pretty(p); + p.push_str("]"); + } Value::Func(v) => v.pretty(p), Value::Any(v) => v.pretty(p), Value::Error => p.push_str("(error)"), |
