summaryrefslogtreecommitdiff
path: root/src/eval/mod.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-01-02 19:37:10 +0100
committerLaurenz <laurmaedje@gmail.com>2021-01-02 19:37:10 +0100
commit1c40dc42e7bc7b799b77f06d25414aca59a044ba (patch)
treeea8bdedaebf59f5bc601346b0108236c7264a29d /src/eval/mod.rs
parent8cad78481cd52680317032c3bb84cacda5666489 (diff)
Dynamic values, Types, Arrays, and Dictionaries 🚀
- Identifiers are now evaluated as variables instead of being plain values - Constants like `left` or `bold` are stored as dynamic values containing the respective rust types - We now distinguish between arrays and dictionaries to make things more intuitive (at the cost of a bit more complex parsing) - Spans were removed from collections (arrays, dictionaries), function arguments still have spans for the top-level values to enable good diagnostics
Diffstat (limited to 'src/eval/mod.rs')
-rw-r--r--src/eval/mod.rs95
1 files changed, 64 insertions, 31 deletions
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index 56946210..62bd444c 100644
--- a/src/eval/mod.rs
+++ b/src/eval/mod.rs
@@ -3,12 +3,10 @@
#[macro_use]
mod value;
mod args;
-mod dict;
mod scope;
mod state;
pub use args::*;
-pub use dict::*;
pub use scope::*;
pub use state::*;
pub use value::*;
@@ -451,7 +449,13 @@ impl Eval for Spanned<&Lit> {
fn eval(self, ctx: &mut EvalContext) -> Self::Output {
match *self.v {
- Lit::Ident(ref v) => Value::Ident(v.clone()),
+ Lit::Ident(ref v) => match ctx.state.scope.get(v.as_str()) {
+ Some(value) => value.clone(),
+ None => {
+ ctx.diag(error!(self.span, "unknown variable"));
+ Value::Error
+ }
+ },
Lit::Bool(v) => Value::Bool(v),
Lit::Int(v) => Value::Int(v),
Lit::Float(v) => Value::Float(v),
@@ -459,28 +463,29 @@ impl Eval for Spanned<&Lit> {
Lit::Percent(v) => Value::Relative(Relative::new(v / 100.0)),
Lit::Color(v) => Value::Color(Color::Rgba(v)),
Lit::Str(ref v) => Value::Str(v.clone()),
+ Lit::Array(ref v) => Value::Array(v.with_span(self.span).eval(ctx)),
Lit::Dict(ref v) => Value::Dict(v.with_span(self.span).eval(ctx)),
Lit::Content(ref v) => Value::Content(v.clone()),
}
}
}
-impl Eval for Spanned<&LitDict> {
- type Output = ValueDict;
+
+impl Eval for Spanned<&Array> {
+ type Output = ValueArray;
fn eval(self, ctx: &mut EvalContext) -> Self::Output {
- let mut dict = ValueDict::new();
+ self.v.iter().map(|expr| expr.as_ref().eval(ctx)).collect()
+ }
+}
- for entry in &self.v.0 {
- let val = entry.expr.as_ref().eval(ctx);
- let spanned = val.with_span(entry.expr.span);
- if let Some(key) = &entry.key {
- dict.insert(&key.v, SpannedEntry::new(key.span, spanned));
- } else {
- dict.push(SpannedEntry::value(spanned));
- }
- }
+impl Eval for Spanned<&Dict> {
+ type Output = ValueDict;
- dict
+ fn eval(self, ctx: &mut EvalContext) -> Self::Output {
+ self.v
+ .iter()
+ .map(|Named { name, expr }| (name.v.0.clone(), expr.as_ref().eval(ctx)))
+ .collect()
}
}
@@ -490,19 +495,27 @@ impl Eval for Spanned<&ExprCall> {
fn eval(self, ctx: &mut EvalContext) -> Self::Output {
let name = &self.v.name.v;
let span = self.v.name.span;
- let dict = self.v.args.as_ref().eval(ctx);
- if let Some(func) = ctx.state.scope.get(name) {
- let args = Args(dict.with_span(self.v.args.span));
- ctx.feedback.decos.push(Deco::Resolved.with_span(span));
- (func.clone())(args, ctx)
- } else {
- if !name.is_empty() {
- ctx.diag(error!(span, "unknown function"));
- ctx.feedback.decos.push(Deco::Unresolved.with_span(span));
+ if let Some(value) = ctx.state.scope.get(name) {
+ if let Value::Func(func) = value {
+ let func = func.clone();
+ ctx.feedback.decos.push(Deco::Resolved.with_span(span));
+
+ let mut args = self.v.args.as_ref().eval(ctx);
+ let returned = func(ctx, &mut args);
+ args.finish(ctx);
+
+ return returned;
+ } else {
+ let ty = value.type_name();
+ ctx.diag(error!(span, "a value of type {} is not callable", ty));
}
- Value::Dict(dict)
+ } else if !name.is_empty() {
+ ctx.diag(error!(span, "unknown function"));
}
+
+ ctx.feedback.decos.push(Deco::Unresolved.with_span(span));
+ Value::Error
}
}
@@ -554,7 +567,7 @@ fn neg(ctx: &mut EvalContext, span: Span, value: Value) -> Value {
Relative(v) => Relative(-v),
Linear(v) => Linear(-v),
v => {
- ctx.diag(error!(span, "cannot negate {}", v.ty()));
+ ctx.diag(error!(span, "cannot negate {}", v.type_name()));
Value::Error
}
}
@@ -589,7 +602,12 @@ fn add(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value {
(Content(a), Content(b)) => Content(concat(a, b)),
(a, b) => {
- ctx.diag(error!(span, "cannot add {} and {}", a.ty(), b.ty()));
+ ctx.diag(error!(
+ span,
+ "cannot add {} and {}",
+ a.type_name(),
+ b.type_name()
+ ));
Value::Error
}
}
@@ -617,7 +635,12 @@ fn sub(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value {
(Linear(a), Linear(b)) => Linear(a - b),
(a, b) => {
- ctx.diag(error!(span, "cannot subtract {1} from {0}", a.ty(), b.ty()));
+ ctx.diag(error!(
+ span,
+ "cannot subtract {1} from {0}",
+ a.type_name(),
+ b.type_name()
+ ));
Value::Error
}
}
@@ -652,7 +675,12 @@ fn mul(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value {
(Str(a), Int(b)) => Str(a.repeat(0.max(b) as usize)),
(a, b) => {
- ctx.diag(error!(span, "cannot multiply {} with {}", a.ty(), b.ty()));
+ ctx.diag(error!(
+ span,
+ "cannot multiply {} with {}",
+ a.type_name(),
+ b.type_name()
+ ));
Value::Error
}
}
@@ -677,7 +705,12 @@ fn div(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value {
(Linear(a), Float(b)) => Linear(a / b),
(a, b) => {
- ctx.diag(error!(span, "cannot divide {} by {}", a.ty(), b.ty()));
+ ctx.diag(error!(
+ span,
+ "cannot divide {} by {}",
+ a.type_name(),
+ b.type_name()
+ ));
Value::Error
}
}