summaryrefslogtreecommitdiff
path: root/src/eval
diff options
context:
space:
mode:
Diffstat (limited to 'src/eval')
-rw-r--r--src/eval/mod.rs200
-rw-r--r--src/eval/ops.rs183
-rw-r--r--src/eval/value.rs24
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)"),