diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-06-18 11:59:05 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-06-18 11:59:05 +0200 |
| commit | bca035172c463e6ac4aaf2591d7d4af2da51c522 (patch) | |
| tree | d17ba4c0208caab1d30f6f2d19821cbd203e37fa /src/eval | |
| parent | 8b6391040e3fb2ab5f739e26f88621d63ad5d3cc (diff) | |
Join semantics
Diffstat (limited to 'src/eval')
| -rw-r--r-- | src/eval/mod.rs | 30 | ||||
| -rw-r--r-- | src/eval/ops.rs | 29 | ||||
| -rw-r--r-- | src/eval/value.rs | 29 |
3 files changed, 58 insertions, 30 deletions
diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 67f710c3..cf02d2a5 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -327,7 +327,8 @@ impl Eval for BlockExpr { let mut output = Value::None; for expr in &self.exprs { - output = expr.eval(ctx); + let value = expr.eval(ctx); + output = output.join(ctx, value, expr.span()); } if self.scoping { @@ -584,19 +585,15 @@ impl Eval for WhileExpr { type Output = Value; fn eval(&self, ctx: &mut EvalContext) -> Self::Output { - let mut output = vec![]; + let mut output = Value::None; loop { let condition = self.condition.eval(ctx); if let Some(condition) = ctx.cast(condition, self.condition.span()) { if condition { - match self.body.eval(ctx) { - Value::Template(v) => output.extend(v), - Value::Str(v) => output.push(TemplateNode::Str(v)), - Value::Error => return Value::Error, - _ => {} - } + let value = self.body.eval(ctx); + output = output.join(ctx, value, self.body.span()); } else { - return Value::Template(output); + return output; } } else { return Value::Error; @@ -611,26 +608,19 @@ impl Eval for ForExpr { fn eval(&self, ctx: &mut EvalContext) -> Self::Output { macro_rules! iter { (for ($($binding:ident => $value:ident),*) in $iter:expr) => {{ - let mut output = vec![]; + let mut output = Value::None; ctx.scopes.enter(); #[allow(unused_parens)] for ($($value),*) in $iter { $(ctx.scopes.def_mut($binding.as_str(), $value);)* - match self.body.eval(ctx) { - Value::Template(v) => output.extend(v), - Value::Str(v) => output.push(TemplateNode::Str(v)), - Value::Error => { - ctx.scopes.exit(); - return Value::Error; - } - _ => {} - } + let value = self.body.eval(ctx); + output = output.join(ctx, value, self.body.span()); } ctx.scopes.exit(); - Value::Template(output) + output }}; } diff --git a/src/eval/ops.rs b/src/eval/ops.rs index b6bd5402..2537f4a5 100644 --- a/src/eval/ops.rs +++ b/src/eval/ops.rs @@ -3,6 +3,33 @@ use std::cmp::Ordering::*; use super::{TemplateNode, Value}; use Value::*; +/// Join a value with another value. +pub fn join(lhs: Value, rhs: Value) -> Result<Value, Value> { + Ok(match (lhs, rhs) { + (_, Error) => Error, + (Error, _) => Error, + + (a, None) => a, + (None, b) => b, + + (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)), + (Template(mut a), Str(b)) => Template({ + a.push(TemplateNode::Str(b)); + a + }), + (Str(a), Template(mut b)) => Template({ + b.insert(0, TemplateNode::Str(a)); + b + }), + + (a, _) => return Err(a), + }) +} + /// Apply the plus operator to a value. pub fn pos(value: Value) -> Value { match value { @@ -60,8 +87,6 @@ pub fn add(lhs: Value, rhs: Value) -> Value { (Dict(a), Dict(b)) => Dict(concat(a, b)), (Template(a), Template(b)) => Template(concat(a, b)), - (Template(a), None) => Template(a), - (None, Template(b)) => Template(b), (Template(mut a), Str(b)) => Template({ a.push(TemplateNode::Str(b)); a diff --git a/src/eval/value.rs b/src/eval/value.rs index f2bc4fd6..b29d01f3 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -5,6 +5,7 @@ use std::fmt::{self, Debug, Display, Formatter}; use std::ops::Deref; use std::rc::Rc; +use super::ops; use super::EvalContext; use crate::color::{Color, RgbaColor}; use crate::exec::ExecContext; @@ -61,14 +62,6 @@ impl Value { Self::Template(vec![TemplateNode::Func(TemplateFunc::new(name, f))]) } - /// Try to cast the value into a specific type. - pub fn cast<T>(self) -> CastResult<T, Self> - where - T: Cast<Value>, - { - T::cast(self) - } - /// The name of the stored value's type. pub fn type_name(&self) -> &'static str { match self { @@ -125,6 +118,26 @@ impl Value { _ => None, } } + + /// Try to cast the value into a specific type. + pub fn cast<T>(self) -> CastResult<T, Self> + where + T: Cast<Value>, + { + T::cast(self) + } + + /// Join with another value. + pub fn join(self, ctx: &mut EvalContext, other: Self, span: Span) -> Self { + let (lhs, rhs) = (self.type_name(), other.type_name()); + match ops::join(self, other) { + Ok(joined) => joined, + Err(prev) => { + ctx.diag(error!(span, "cannot join {} with {}", lhs, rhs)); + prev + } + } + } } impl Default for Value { |
