summaryrefslogtreecommitdiff
path: root/src/eval
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-07-08 23:36:20 +0200
committerLaurenz <laurmaedje@gmail.com>2021-07-08 23:36:20 +0200
commit0c74290519ee999002e9cc99ba3d272d68e1014f (patch)
tree8134b8aeabb9d5af4c50667de6b2c6532c6b8422 /src/eval
parent02b586cc36fad58a622ecb439e1cf3a76a347207 (diff)
Compare functions and templates by identity
Diffstat (limited to 'src/eval')
-rw-r--r--src/eval/mod.rs5
-rw-r--r--src/eval/ops.rs97
-rw-r--r--src/eval/value.rs22
3 files changed, 56 insertions, 68 deletions
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index ba2de8c7..4992f70c 100644
--- a/src/eval/mod.rs
+++ b/src/eval/mod.rs
@@ -229,7 +229,10 @@ impl Eval for Rc<SyntaxTree> {
let mut visitor = ExprVisitor { ctx, map: ExprMap::new() };
visitor.visit_tree(self);
- vec![TemplateNode::Tree { tree: Rc::clone(self), map: visitor.map }]
+ Rc::new(vec![TemplateNode::Tree {
+ tree: Rc::clone(self),
+ map: visitor.map,
+ }])
}
}
diff --git a/src/eval/ops.rs b/src/eval/ops.rs
index 01044842..3b48140c 100644
--- a/src/eval/ops.rs
+++ b/src/eval/ops.rs
@@ -1,35 +1,9 @@
use std::cmp::Ordering::*;
+use std::rc::Rc;
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 {
@@ -82,21 +56,7 @@ pub fn add(lhs: Value, rhs: Value) -> Value {
(Fractional(a), Fractional(b)) => Fractional(a + 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
- }),
-
- _ => Error,
+ (a, b) => concat(a, b).unwrap_or(Value::Error),
}
}
@@ -130,6 +90,11 @@ pub fn sub(lhs: Value, rhs: Value) -> Value {
/// Compute the product of two values.
pub fn mul(lhs: Value, rhs: Value) -> Value {
+ fn repeat<T: Clone>(vec: Vec<T>, n: usize) -> Vec<T> {
+ let len = n * vec.len();
+ vec.into_iter().cycle().take(len).collect()
+ }
+
match (lhs, rhs) {
(Int(a), Int(b)) => Int(a * b),
(Int(a), Float(b)) => Float(a as f64 * b),
@@ -258,17 +223,43 @@ pub fn range(lhs: Value, rhs: Value) -> Value {
}
}
-/// Concatenate two collections.
-fn concat<T, A>(mut a: T, b: T) -> T
-where
- T: Extend<A> + IntoIterator<Item = A>,
-{
- a.extend(b);
- a
+/// 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,
+
+ (a, b) => return concat(a, b),
+ })
}
-/// Repeat a vector `n` times.
-fn repeat<T: Clone>(vec: Vec<T>, n: usize) -> Vec<T> {
- let len = n * vec.len();
- vec.into_iter().cycle().take(len).collect()
+/// Concatentate two values.
+fn concat(lhs: Value, rhs: Value) -> Result<Value, Value> {
+ Ok(match (lhs, rhs) {
+ (Str(a), Str(b)) => Str(a + &b),
+ (Array(mut a), Array(b)) => Array({
+ a.extend(b);
+ a
+ }),
+ (Dict(mut a), Dict(b)) => Dict({
+ a.extend(b);
+ a
+ }),
+ (Template(mut a), Template(b)) => Template({
+ Rc::make_mut(&mut a).extend(b.iter().cloned());
+ a
+ }),
+ (Template(mut a), Str(b)) => Template({
+ Rc::make_mut(&mut a).push(TemplateNode::Str(b));
+ a
+ }),
+ (Str(a), Template(mut b)) => Template({
+ Rc::make_mut(&mut b).insert(0, TemplateNode::Str(a));
+ b
+ }),
+ (a, _) => return Err(a),
+ })
}
diff --git a/src/eval/value.rs b/src/eval/value.rs
index 472df0ea..07552c84 100644
--- a/src/eval/value.rs
+++ b/src/eval/value.rs
@@ -59,7 +59,7 @@ impl Value {
where
F: Fn(&mut ExecContext) + 'static,
{
- Self::Template(vec![TemplateNode::Func(TemplateFunc::new(f))])
+ Self::Template(Rc::new(vec![TemplateNode::Func(TemplateFunc::new(f))]))
}
/// The name of the stored value's type.
@@ -102,6 +102,7 @@ impl Value {
a.len() == b.len()
&& a.iter().all(|(k, x)| b.get(k).map_or(false, |y| x.eq(y)))
}
+ (Self::Template(a), Self::Template(b)) => Rc::ptr_eq(a, b),
(a, b) => a == b,
}
}
@@ -153,7 +154,7 @@ pub type ArrayValue = Vec<Value>;
pub type DictValue = BTreeMap<String, Value>;
/// A template value: `[*Hi* there]`.
-pub type TemplateValue = Vec<TemplateNode>;
+pub type TemplateValue = Rc<Vec<TemplateNode>>;
/// One chunk of a template.
///
@@ -177,7 +178,6 @@ pub enum TemplateNode {
impl PartialEq for TemplateNode {
fn eq(&self, _: &Self) -> bool {
- // TODO: Figure out what we want here.
false
}
}
@@ -205,13 +205,6 @@ impl TemplateFunc {
}
}
-impl PartialEq for TemplateFunc {
- fn eq(&self, _: &Self) -> bool {
- // TODO: Figure out what we want here.
- false
- }
-}
-
impl Deref for TemplateFunc {
type Target = dyn Fn(&mut ExecContext);
@@ -232,6 +225,7 @@ pub struct FuncValue {
/// The string is boxed to make the whole struct fit into 24 bytes, so that
/// a [`Value`] fits into 32 bytes.
name: Option<Box<String>>,
+ /// The closure that defines the function.
f: Rc<dyn Fn(&mut EvalContext, &mut FuncArgs) -> Value>,
}
@@ -251,9 +245,9 @@ impl FuncValue {
}
impl PartialEq for FuncValue {
- fn eq(&self, _: &Self) -> bool {
- // TODO: Figure out what we want here.
- false
+ fn eq(&self, other: &Self) -> bool {
+ // We cast to thin pointers because we don't want to compare vtables.
+ Rc::as_ptr(&self.f) as *const () == Rc::as_ptr(&other.f) as *const ()
}
}
@@ -620,7 +614,7 @@ primitive! { DictValue: "dictionary", Value::Dict }
primitive! {
TemplateValue: "template",
Value::Template,
- Value::Str(v) => vec![TemplateNode::Str(v)],
+ Value::Str(v) => Rc::new(vec![TemplateNode::Str(v)]),
}
primitive! { FuncValue: "function", Value::Func }