mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Compare functions and templates by identity
This commit is contained in:
parent
02b586cc36
commit
0c74290519
@ -229,7 +229,10 @@ impl Eval for Rc<SyntaxTree> {
|
|||||||
let mut visitor = ExprVisitor { ctx, map: ExprMap::new() };
|
let mut visitor = ExprVisitor { ctx, map: ExprMap::new() };
|
||||||
visitor.visit_tree(self);
|
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,
|
||||||
|
}])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,35 +1,9 @@
|
|||||||
use std::cmp::Ordering::*;
|
use std::cmp::Ordering::*;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use super::{TemplateNode, Value};
|
use super::{TemplateNode, Value};
|
||||||
use 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.
|
/// Apply the plus operator to a value.
|
||||||
pub fn pos(value: Value) -> Value {
|
pub fn pos(value: Value) -> Value {
|
||||||
match value {
|
match value {
|
||||||
@ -82,21 +56,7 @@ pub fn add(lhs: Value, rhs: Value) -> Value {
|
|||||||
|
|
||||||
(Fractional(a), Fractional(b)) => Fractional(a + b),
|
(Fractional(a), Fractional(b)) => Fractional(a + b),
|
||||||
|
|
||||||
(Str(a), Str(b)) => Str(a + &b),
|
(a, b) => concat(a, b).unwrap_or(Value::Error),
|
||||||
(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,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,6 +90,11 @@ pub fn sub(lhs: Value, rhs: Value) -> Value {
|
|||||||
|
|
||||||
/// Compute the product of two values.
|
/// Compute the product of two values.
|
||||||
pub fn mul(lhs: Value, rhs: Value) -> Value {
|
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) {
|
match (lhs, rhs) {
|
||||||
(Int(a), Int(b)) => Int(a * b),
|
(Int(a), Int(b)) => Int(a * b),
|
||||||
(Int(a), Float(b)) => Float(a as f64 * 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.
|
/// Join a value with another value.
|
||||||
fn concat<T, A>(mut a: T, b: T) -> T
|
pub fn join(lhs: Value, rhs: Value) -> Result<Value, Value> {
|
||||||
where
|
Ok(match (lhs, rhs) {
|
||||||
T: Extend<A> + IntoIterator<Item = A>,
|
(_, Error) => Error,
|
||||||
{
|
(Error, _) => Error,
|
||||||
a.extend(b);
|
|
||||||
a
|
(a, None) => a,
|
||||||
|
(None, b) => b,
|
||||||
|
|
||||||
|
(a, b) => return concat(a, b),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Repeat a vector `n` times.
|
/// Concatentate two values.
|
||||||
fn repeat<T: Clone>(vec: Vec<T>, n: usize) -> Vec<T> {
|
fn concat(lhs: Value, rhs: Value) -> Result<Value, Value> {
|
||||||
let len = n * vec.len();
|
Ok(match (lhs, rhs) {
|
||||||
vec.into_iter().cycle().take(len).collect()
|
(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),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ impl Value {
|
|||||||
where
|
where
|
||||||
F: Fn(&mut ExecContext) + 'static,
|
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.
|
/// The name of the stored value's type.
|
||||||
@ -102,6 +102,7 @@ impl Value {
|
|||||||
a.len() == b.len()
|
a.len() == b.len()
|
||||||
&& a.iter().all(|(k, x)| b.get(k).map_or(false, |y| x.eq(y)))
|
&& 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,
|
(a, b) => a == b,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -153,7 +154,7 @@ pub type ArrayValue = Vec<Value>;
|
|||||||
pub type DictValue = BTreeMap<String, Value>;
|
pub type DictValue = BTreeMap<String, Value>;
|
||||||
|
|
||||||
/// A template value: `[*Hi* there]`.
|
/// A template value: `[*Hi* there]`.
|
||||||
pub type TemplateValue = Vec<TemplateNode>;
|
pub type TemplateValue = Rc<Vec<TemplateNode>>;
|
||||||
|
|
||||||
/// One chunk of a template.
|
/// One chunk of a template.
|
||||||
///
|
///
|
||||||
@ -177,7 +178,6 @@ pub enum TemplateNode {
|
|||||||
|
|
||||||
impl PartialEq for TemplateNode {
|
impl PartialEq for TemplateNode {
|
||||||
fn eq(&self, _: &Self) -> bool {
|
fn eq(&self, _: &Self) -> bool {
|
||||||
// TODO: Figure out what we want here.
|
|
||||||
false
|
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 {
|
impl Deref for TemplateFunc {
|
||||||
type Target = dyn Fn(&mut ExecContext);
|
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
|
/// The string is boxed to make the whole struct fit into 24 bytes, so that
|
||||||
/// a [`Value`] fits into 32 bytes.
|
/// a [`Value`] fits into 32 bytes.
|
||||||
name: Option<Box<String>>,
|
name: Option<Box<String>>,
|
||||||
|
/// The closure that defines the function.
|
||||||
f: Rc<dyn Fn(&mut EvalContext, &mut FuncArgs) -> Value>,
|
f: Rc<dyn Fn(&mut EvalContext, &mut FuncArgs) -> Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,9 +245,9 @@ impl FuncValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for FuncValue {
|
impl PartialEq for FuncValue {
|
||||||
fn eq(&self, _: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
// TODO: Figure out what we want here.
|
// We cast to thin pointers because we don't want to compare vtables.
|
||||||
false
|
Rc::as_ptr(&self.f) as *const () == Rc::as_ptr(&other.f) as *const ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -620,7 +614,7 @@ primitive! { DictValue: "dictionary", Value::Dict }
|
|||||||
primitive! {
|
primitive! {
|
||||||
TemplateValue: "template",
|
TemplateValue: "template",
|
||||||
Value::Template,
|
Value::Template,
|
||||||
Value::Str(v) => vec![TemplateNode::Str(v)],
|
Value::Str(v) => Rc::new(vec![TemplateNode::Str(v)]),
|
||||||
}
|
}
|
||||||
primitive! { FuncValue: "function", Value::Func }
|
primitive! { FuncValue: "function", Value::Func }
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ impl Exec for Value {
|
|||||||
|
|
||||||
impl Exec for TemplateValue {
|
impl Exec for TemplateValue {
|
||||||
fn exec(&self, ctx: &mut ExecContext) {
|
fn exec(&self, ctx: &mut ExecContext) {
|
||||||
for node in self {
|
for node in self.iter() {
|
||||||
node.exec(ctx);
|
node.exec(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,6 +112,7 @@
|
|||||||
---
|
---
|
||||||
// Test equality operators.
|
// Test equality operators.
|
||||||
|
|
||||||
|
// Most things compare by value.
|
||||||
#test(1 == "hi", false)
|
#test(1 == "hi", false)
|
||||||
#test(1 == 1.0, true)
|
#test(1 == 1.0, true)
|
||||||
#test(30% == 30% + 0cm, true)
|
#test(30% == 30% + 0cm, true)
|
||||||
@ -124,6 +125,17 @@
|
|||||||
#test((a: 2 - 1.0, b: 2) == (b: 2, a: 1), true)
|
#test((a: 2 - 1.0, b: 2) == (b: 2, a: 1), true)
|
||||||
#test("a" != "a", false)
|
#test("a" != "a", false)
|
||||||
|
|
||||||
|
// Functions compare by identity.
|
||||||
|
#test(test == test, true)
|
||||||
|
#test((() => {}) == (() => {}), false)
|
||||||
|
|
||||||
|
// Templates also compare by identity.
|
||||||
|
#let t = [a]
|
||||||
|
#test(t == t, true)
|
||||||
|
#test([] == [], false)
|
||||||
|
#test([] == [a], false)
|
||||||
|
#test([a] == [a], false)
|
||||||
|
|
||||||
---
|
---
|
||||||
// Test comparison operators.
|
// Test comparison operators.
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user