From f4460f8abd7dee1806cf59b4d3777581a6ed154a Mon Sep 17 00:00:00 2001 From: Laurenz Date: Sun, 4 Oct 2020 19:21:35 +0200 Subject: [PATCH] =?UTF-8?q?Style=20nits=20=F0=9F=8E=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/eval/dict.rs | 2 +- src/eval/scope.rs | 8 +-- src/eval/value.rs | 154 ++++++++++++++++++++--------------------- src/library/align.rs | 2 +- src/library/boxed.rs | 2 +- src/library/color.rs | 2 +- src/library/font.rs | 4 +- src/library/mod.rs | 4 +- src/library/page.rs | 10 +-- src/library/spacing.rs | 6 +- src/prelude.rs | 2 +- src/syntax/ast/expr.rs | 91 ++++++++++++------------ src/syntax/ast/lit.rs | 30 ++++---- src/syntax/ast/mod.rs | 2 + src/syntax/ast/tree.rs | 2 +- 15 files changed, 161 insertions(+), 160 deletions(-) diff --git a/src/eval/dict.rs b/src/eval/dict.rs index b0d5fb825..8d926833d 100644 --- a/src/eval/dict.rs +++ b/src/eval/dict.rs @@ -351,7 +351,7 @@ impl SpannedEntry { } /// Create an entry with the same span for key and value. - pub fn val(val: Spanned) -> Self { + pub fn value(val: Spanned) -> Self { Self { key_span: val.span, value: val } } diff --git a/src/eval/scope.rs b/src/eval/scope.rs index d4b248800..7d69e1fcb 100644 --- a/src/eval/scope.rs +++ b/src/eval/scope.rs @@ -3,12 +3,12 @@ use std::collections::HashMap; use std::fmt::{self, Debug, Formatter}; -use super::value::FuncValue; +use super::value::ValueFunc; /// A map from identifiers to functions. #[derive(Clone, PartialEq)] pub struct Scope { - functions: HashMap, + functions: HashMap, } impl Scope { @@ -19,12 +19,12 @@ impl Scope { } /// Associate the given name with the function. - pub fn insert(&mut self, name: impl Into, function: FuncValue) { + pub fn insert(&mut self, name: impl Into, function: ValueFunc) { self.functions.insert(name.into(), function); } /// Return the function with the given name if there is one. - pub fn func(&self, name: &str) -> Option<&FuncValue> { + pub fn func(&self, name: &str) -> Option<&ValueFunc> { self.functions.get(name) } } diff --git a/src/eval/value.rs b/src/eval/value.rs index f88c07044..bb091b6e4 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -17,8 +17,6 @@ use crate::{DynFuture, Feedback}; /// A computational value. #[derive(Clone, PartialEq)] pub enum Value { - /// The result of invalid operations. - Error, /// An identifier: `ident`. Ident(Ident), /// A boolean: `true, false`. @@ -36,27 +34,29 @@ pub enum Value { /// /// [literal]: ../syntax/ast/enum.Lit.html#variant.Percent Relative(f64), - /// A combination of an absolute length and a relative value. + /// A combination of an absolute length and a relative value: `20% + 5cm`. Linear(Linear), /// A color value with alpha channel: `#f79143ff`. Color(RgbaColor), /// A string: `"string"`. Str(String), /// A dictionary value: `(false, 12cm, greeting="hi")`. - Dict(DictValue), - /// A syntax tree containing typesetting content. - Tree(SynTree), + Dict(ValueDict), + /// A content value: `{*Hi* there}`. + Content(SynTree), /// An executable function. - Func(FuncValue), + Func(ValueFunc), /// Layouting commands. Commands(Commands), + /// The result of invalid operations. + Error, } impl Value { - /// The natural-language name of this value for use in error messages. - pub fn name(&self) -> &'static str { + /// The natural-language name of this value's type for use in error + /// messages. + pub fn ty(&self) -> &'static str { match self { - Self::Error => "error", Self::Ident(_) => "identifier", Self::Bool(_) => "bool", Self::Int(_) => "integer", @@ -67,9 +67,10 @@ impl Value { Self::Color(_) => "color", Self::Str(_) => "string", Self::Dict(_) => "dict", - Self::Tree(_) => "syntax tree", + Self::Content(_) => "content", Self::Func(_) => "function", Self::Commands(_) => "commands", + Self::Error => "error", } } } @@ -98,7 +99,7 @@ impl Spanned { commands } - Value::Tree(tree) => vec![Command::LayoutSyntaxTree(tree)], + Value::Content(tree) => vec![Command::LayoutSyntaxTree(tree)], Value::Commands(commands) => commands, // Format with debug. @@ -115,69 +116,67 @@ impl Debug for Value { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { Self::Error => f.pad(""), - Self::Ident(i) => i.fmt(f), - Self::Bool(b) => b.fmt(f), - Self::Int(i) => i.fmt(f), - Self::Float(n) => n.fmt(f), - Self::Length(l) => l.fmt(f), - Self::Relative(r) => r.fmt(f), - Self::Linear(l) => l.fmt(f), - Self::Color(c) => c.fmt(f), - Self::Str(s) => s.fmt(f), - Self::Dict(d) => d.fmt(f), - Self::Tree(t) => t.fmt(f), - Self::Func(c) => c.fmt(f), - Self::Commands(c) => c.fmt(f), + Self::Ident(v) => v.fmt(f), + Self::Bool(v) => v.fmt(f), + Self::Int(v) => v.fmt(f), + Self::Float(v) => v.fmt(f), + Self::Length(v) => v.fmt(f), + Self::Relative(v) => v.fmt(f), + Self::Linear(v) => v.fmt(f), + Self::Color(v) => v.fmt(f), + Self::Str(v) => v.fmt(f), + Self::Dict(v) => v.fmt(f), + Self::Content(v) => v.fmt(f), + Self::Func(v) => v.fmt(f), + Self::Commands(v) => v.fmt(f), } } } -/// An executable function value. -/// -/// The first argument is a dictionary containing the arguments passed to the -/// function. The function may be asynchronous (as such it returns a dynamic -/// future) and it may emit diagnostics, which are contained in the returned -/// `Pass`. In the end, the function must evaluate to [`Value`]. A typical -/// typesetting function will return a `Commands` value which will instruct the -/// layouting engine to do what the function pleases. +/// An wrapper around a reference-counted executable function value. /// /// The dynamic function object is wrapped in an `Rc` to keep [`Value`] /// clonable. /// +/// _Note_: This is needed because the compiler can't `derive(PartialEq)` +/// for `Value` when directly putting the boxed function in there, +/// see the [Rust Issue]. +/// /// [`Value`]: enum.Value.html +/// [Rust Issue]: https://github.com/rust-lang/rust/issues/31740 #[derive(Clone)] -pub struct FuncValue(pub Rc); +pub struct ValueFunc(pub Rc); /// The signature of executable functions. -type FuncType = dyn Fn(DictValue, &mut LayoutContext) -> DynFuture; +pub type Func = dyn Fn(ValueDict, &mut LayoutContext) -> DynFuture; -impl FuncValue { +impl ValueFunc { /// Create a new function value from a rust function or closure. pub fn new(f: F) -> Self where - F: Fn(DictValue, &mut LayoutContext) -> DynFuture, + F: Fn(ValueDict, &mut LayoutContext) -> DynFuture, { Self(Rc::new(f)) } } -impl Eq for FuncValue {} +impl Eq for ValueFunc {} -impl PartialEq for FuncValue { +impl PartialEq for ValueFunc { fn eq(&self, other: &Self) -> bool { Rc::ptr_eq(&self.0, &other.0) } } -impl Deref for FuncValue { - type Target = FuncType; +impl Deref for ValueFunc { + type Target = Func; fn deref(&self) -> &Self::Target { self.0.as_ref() } } -impl Debug for FuncValue { +impl Debug for ValueFunc { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.pad("") } @@ -189,9 +188,9 @@ impl Debug for FuncValue { /// ```typst /// (false, 12cm, greeting="hi") /// ``` -pub type DictValue = Dict>; +pub type ValueDict = Dict>; -impl DictValue { +impl ValueDict { /// Retrieve and remove the matching value with the lowest number key, /// skipping and ignoring all non-matching entries with lower keys. pub fn take(&mut self) -> Option { @@ -331,7 +330,7 @@ macro_rules! impl_match { other => { error!( @f, value.span, - "expected {}, found {}", $name, other.name() + "expected {}, found {}", $name, other.ty() ); None } @@ -354,7 +353,7 @@ macro_rules! impl_ident { } else { error!( @f, value.span, - "expected {}, found {}", $name, value.v.name() + "expected {}, found {}", $name, value.v.ty() ); None } @@ -370,33 +369,13 @@ impl TryFromValue for Spanned { } } -impl_match!(Value, "value", v => v.clone()); -impl_match!(Ident, "identifier", Value::Ident(i) => i.clone()); -impl_match!(bool, "bool", &Value::Bool(b) => b); -impl_match!(i64, "integer", &Value::Int(i) => i); -impl_match!(f64, "float", - &Value::Int(i) => i as f64, - &Value::Float(f) => f, -); -impl_match!(Abs, "length", &Value::Length(l) => Abs(l)); -impl_match!(Rel, "relative", &Value::Relative(r) => Rel(r)); -impl_match!(Linear, "linear", - &Value::Linear(l) => l, - &Value::Length(l) => Linear::abs(l), - &Value::Relative(r) => Linear::rel(r), -); -impl_match!(String, "string", Value::Str(s) => s.clone()); -impl_match!(SynTree, "tree", Value::Tree(t) => t.clone()); -impl_match!(DictValue, "dict", Value::Dict(t) => t.clone()); -impl_match!(FuncValue, "function", Value::Func(f) => f.clone()); - /// A value type that matches [length] values. /// /// [length]: enum.Value.html#variant.Length -pub struct Abs(pub f64); +pub struct Absolute(pub f64); -impl From for f64 { - fn from(abs: Abs) -> f64 { +impl From for f64 { + fn from(abs: Absolute) -> f64 { abs.0 } } @@ -404,10 +383,10 @@ impl From for f64 { /// A value type that matches [relative] values. /// /// [relative]: enum.Value.html#variant.Relative -pub struct Rel(pub f64); +pub struct Relative(pub f64); -impl From for f64 { - fn from(rel: Rel) -> f64 { +impl From for f64 { + fn from(rel: Relative) -> f64 { rel.0 } } @@ -432,12 +411,31 @@ impl Deref for StringLike { } } +impl_match!(Value, "value", v => v.clone()); +impl_match!(Ident, "identifier", Value::Ident(v) => v.clone()); +impl_match!(bool, "bool", &Value::Bool(v) => v); +impl_match!(i64, "integer", &Value::Int(v) => v); +impl_match!(f64, "float", + &Value::Int(v) => v as f64, + &Value::Float(v) => v, +); +impl_match!(Absolute, "length", &Value::Length(v) => Absolute(v)); +impl_match!(Relative, "relative", &Value::Relative(v) => Relative(v)); +impl_match!(Linear, "linear", + &Value::Linear(v) => v, + &Value::Length(v) => Linear::abs(v), + &Value::Relative(v) => Linear::rel(v), +); +impl_match!(String, "string", Value::Str(v) => v.clone()); +impl_match!(SynTree, "tree", Value::Content(v) => v.clone()); +impl_match!(ValueDict, "dict", Value::Dict(v) => v.clone()); +impl_match!(ValueFunc, "function", Value::Func(v) => v.clone()); impl_match!(StringLike, "identifier or string", - Value::Ident(Ident(s)) => StringLike(s.clone()), - Value::Str(s) => StringLike(s.clone()), + Value::Ident(Ident(v)) => StringLike(v.clone()), + Value::Str(v) => StringLike(v.clone()), ); -impl_ident!(Dir, "direction", |s| match s { +impl_ident!(Dir, "direction", |v| match v { "ltr" => Some(Self::LTR), "rtl" => Some(Self::RTL), "ttb" => Some(Self::TTB), @@ -445,7 +443,7 @@ impl_ident!(Dir, "direction", |s| match s { _ => None, }); -impl_ident!(SpecAlign, "alignment", |s| match s { +impl_ident!(SpecAlign, "alignment", |v| match v { "left" => Some(Self::Left), "right" => Some(Self::Right), "top" => Some(Self::Top), @@ -486,7 +484,7 @@ impl TryFromValue for FontWeight { error!( @f, value.span, "expected font weight (name or integer), found {}", - other.name(), + other.ty(), ); None } @@ -499,7 +497,7 @@ mod tests { use super::*; fn entry(value: Value) -> SpannedEntry { - SpannedEntry::val(Spanned::zero(value)) + SpannedEntry::value(Spanned::zero(value)) } #[test] diff --git a/src/library/align.rs b/src/library/align.rs index c3512b7fc..0c145e5f0 100644 --- a/src/library/align.rs +++ b/src/library/align.rs @@ -14,7 +14,7 @@ use super::*; /// - `vertical`: Any of `top`, `bottom` or `center`. /// /// There may not be two alignment specifications for the same axis. -pub async fn align(mut args: DictValue, ctx: &mut LayoutContext) -> Value { +pub async fn align(mut args: ValueDict, ctx: &mut LayoutContext) -> Value { let content = args.take::(); let h = args.take_key::>("horizontal", &mut ctx.f); let v = args.take_key::>("vertical", &mut ctx.f); diff --git a/src/library/boxed.rs b/src/library/boxed.rs index 94aac48a7..c97df8d0b 100644 --- a/src/library/boxed.rs +++ b/src/library/boxed.rs @@ -6,7 +6,7 @@ use crate::geom::Linear; /// # Keyword arguments /// - `width`: The width of the box (length or relative to parent's width). /// - `height`: The height of the box (length or relative to parent's height). -pub async fn boxed(mut args: DictValue, ctx: &mut LayoutContext) -> Value { +pub async fn boxed(mut args: ValueDict, ctx: &mut LayoutContext) -> Value { let content = args.take::().unwrap_or_default(); let constraints = &mut ctx.constraints; diff --git a/src/library/color.rs b/src/library/color.rs index 631c36684..22029b1fd 100644 --- a/src/library/color.rs +++ b/src/library/color.rs @@ -2,7 +2,7 @@ use super::*; use crate::color::RgbaColor; /// `rgb`: Create an RGB(A) color. -pub async fn rgb(mut args: DictValue, ctx: &mut LayoutContext) -> Value { +pub async fn rgb(mut args: ValueDict, ctx: &mut LayoutContext) -> Value { let mut f = Feedback::new(); let r = args.expect::>("red value", Span::ZERO, &mut f); diff --git a/src/library/font.rs b/src/library/font.rs index 40d8d30b6..cfda3beb6 100644 --- a/src/library/font.rs +++ b/src/library/font.rs @@ -49,7 +49,7 @@ use crate::geom::Linear; /// ```typst /// [font: "My Serif", serif] /// ``` -pub async fn font(mut args: DictValue, ctx: &mut LayoutContext) -> Value { +pub async fn font(mut args: ValueDict, ctx: &mut LayoutContext) -> Value { let mut text = ctx.state.text.clone(); let mut updated_fallback = false; @@ -86,7 +86,7 @@ pub async fn font(mut args: DictValue, ctx: &mut LayoutContext) -> Value { text.variant.stretch = stretch; } - for (class, mut dict) in args.take_all_str::() { + for (class, mut dict) in args.take_all_str::() { let fallback = dict .take_all_num_vals::() .map(|s| s.to_lowercase()) diff --git a/src/library/mod.rs b/src/library/mod.rs index 4db544e93..c6dfb758f 100644 --- a/src/library/mod.rs +++ b/src/library/mod.rs @@ -14,7 +14,7 @@ pub use font::*; pub use page::*; pub use spacing::*; -use crate::eval::{FuncValue, Scope}; +use crate::eval::{Scope, ValueFunc}; use crate::prelude::*; macro_rules! std { @@ -30,7 +30,7 @@ macro_rules! std { macro_rules! wrap { ($func:expr) => { - FuncValue::new(|args, ctx| Box::pin($func(args, ctx))) + ValueFunc::new(|args, ctx| Box::pin($func(args, ctx))) }; } diff --git a/src/library/page.rs b/src/library/page.rs index 5fda9d5d7..b557650bc 100644 --- a/src/library/page.rs +++ b/src/library/page.rs @@ -1,7 +1,7 @@ use std::mem; use super::*; -use crate::eval::Abs; +use crate::eval::Absolute; use crate::geom::{Linear, Sides}; use crate::paper::{Paper, PaperClass}; @@ -19,7 +19,7 @@ use crate::paper::{Paper, PaperClass}; /// - `top`: The top margin (length or relative to height). /// - `bottom`: The bottom margin (length or relative to height). /// - `flip`: Flips custom or paper-defined width and height (boolean). -pub async fn page(mut args: DictValue, ctx: &mut LayoutContext) -> Value { +pub async fn page(mut args: ValueDict, ctx: &mut LayoutContext) -> Value { let mut page = ctx.state.page.clone(); if let Some(paper) = args.take::() { @@ -27,12 +27,12 @@ pub async fn page(mut args: DictValue, ctx: &mut LayoutContext) -> Value { page.size = paper.size(); } - if let Some(Abs(width)) = args.take_key::("width", &mut ctx.f) { + if let Some(Absolute(width)) = args.take_key::("width", &mut ctx.f) { page.class = PaperClass::Custom; page.size.width = width; } - if let Some(Abs(height)) = args.take_key::("height", &mut ctx.f) { + if let Some(Absolute(height)) = args.take_key::("height", &mut ctx.f) { page.class = PaperClass::Custom; page.size.height = height; } @@ -66,7 +66,7 @@ pub async fn page(mut args: DictValue, ctx: &mut LayoutContext) -> Value { } /// `pagebreak`: Ends the current page. -pub async fn pagebreak(args: DictValue, ctx: &mut LayoutContext) -> Value { +pub async fn pagebreak(args: ValueDict, ctx: &mut LayoutContext) -> Value { args.unexpected(&mut ctx.f); Value::Commands(vec![BreakPage]) } diff --git a/src/library/spacing.rs b/src/library/spacing.rs index 91f407fe8..9ca682638 100644 --- a/src/library/spacing.rs +++ b/src/library/spacing.rs @@ -6,7 +6,7 @@ use crate::layout::SpacingKind; /// /// # Positional arguments /// - The spacing (length or relative to font size). -pub async fn h(args: DictValue, ctx: &mut LayoutContext) -> Value { +pub async fn h(args: ValueDict, ctx: &mut LayoutContext) -> Value { spacing(args, ctx, SpecAxis::Horizontal) } @@ -14,11 +14,11 @@ pub async fn h(args: DictValue, ctx: &mut LayoutContext) -> Value { /// /// # Positional arguments /// - The spacing (length or relative to font size). -pub async fn v(args: DictValue, ctx: &mut LayoutContext) -> Value { +pub async fn v(args: ValueDict, ctx: &mut LayoutContext) -> Value { spacing(args, ctx, SpecAxis::Vertical) } -fn spacing(mut args: DictValue, ctx: &mut LayoutContext, axis: SpecAxis) -> Value { +fn spacing(mut args: ValueDict, ctx: &mut LayoutContext, axis: SpecAxis) -> Value { let spacing = args.expect::("spacing", Span::ZERO, &mut ctx.f); args.unexpected(&mut ctx.f); Value::Commands(if let Some(spacing) = spacing { diff --git a/src/prelude.rs b/src/prelude.rs index 84c5859bd..f31288443 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,7 +1,7 @@ //! A prelude for building custom functions. #[doc(no_inline)] -pub use crate::eval::{Dict, DictValue, Value}; +pub use crate::eval::{Dict, Value, ValueDict}; pub use crate::layout::primitive::*; #[doc(no_inline)] pub use crate::layout::{layout_tree, Command, Commands, LayoutContext}; diff --git a/src/syntax/ast/expr.rs b/src/syntax/ast/expr.rs index 5cd5187b0..718b0568c 100644 --- a/src/syntax/ast/expr.rs +++ b/src/syntax/ast/expr.rs @@ -1,8 +1,8 @@ //! Expressions. +use super::*; use crate::eval::Value; use crate::layout::LayoutContext; -use crate::syntax::{Decoration, Ident, Lit, LitDict, SpanWith, Spanned}; use crate::DynFuture; /// An expression. @@ -10,12 +10,12 @@ use crate::DynFuture; pub enum Expr { /// A literal: `true`, `1cm`, `"hi"`, `{_Hey!_}`. Lit(Lit), + /// An invocation of a function: `[foo: ...]`, `foo(...)`. + Call(ExprCall), /// A unary operation: `-x`. Unary(ExprUnary), /// A binary operation: `a + b`, `a / b`. Binary(ExprBinary), - /// An invocation of a function: `[foo: ...]`, `foo(...)`. - Call(ExprCall), } impl Expr { @@ -24,14 +24,43 @@ impl Expr { Box::pin(async move { match self { Self::Lit(lit) => lit.eval(ctx).await, + Self::Call(call) => call.eval(ctx).await, Self::Unary(unary) => unary.eval(ctx).await, Self::Binary(binary) => binary.eval(ctx).await, - Self::Call(call) => call.eval(ctx).await, } }) } } +/// An invocation of a function: `[foo: ...]`, `foo(...)`. +#[derive(Debug, Clone, PartialEq)] +pub struct ExprCall { + /// The name of the function. + pub name: Spanned, + /// The arguments to the function. + pub args: LitDict, +} + +impl ExprCall { + /// Evaluate the call expression to a value. + pub async fn eval(&self, ctx: &mut LayoutContext) -> Value { + let name = &self.name.v; + let span = self.name.span; + let args = self.args.eval(ctx).await; + + if let Some(func) = ctx.state.scope.func(name) { + ctx.f.decorations.push(Decoration::Resolved.span_with(span)); + (func.clone())(args, ctx).await + } else { + if !name.is_empty() { + error!(@ctx.f, span, "unknown function"); + ctx.f.decorations.push(Decoration::Unresolved.span_with(span)); + } + Value::Dict(args) + } + } +} + /// A unary operation: `-x`. #[derive(Debug, Clone, PartialEq)] pub struct ExprUnary { @@ -54,13 +83,13 @@ impl ExprUnary { let span = self.op.span.join(self.expr.span); match self.op.v { UnOp::Neg => match value { - Int(x) => Int(-x), - Float(x) => Float(-x), - Length(x) => Length(-x), - Relative(x) => Relative(-x), - Linear(x) => Linear(-x), + Int(v) => Int(-v), + Float(v) => Float(-v), + Length(v) => Length(-v), + Relative(v) => Relative(-v), + Linear(v) => Linear(-v), v => { - error!(@ctx.f, span, "cannot negate {}", v.name()); + error!(@ctx.f, span, "cannot negate {}", v.ty()); Value::Error } }, @@ -104,7 +133,8 @@ impl ExprBinary { BinOp::Add => match (lhs, rhs) { // Numbers to themselves. (Int(a), Int(b)) => Int(a + b), - (Int(i), Float(f)) | (Float(f), Int(i)) => Float(i as f64 + f), + (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. @@ -123,11 +153,11 @@ impl ExprBinary { // Complex data types to themselves. (Str(a), Str(b)) => Str(a + &b), (Dict(a), Dict(b)) => Dict(concat(a, b)), - (Tree(a), Tree(b)) => Tree(concat(a, b)), + (Content(a), Content(b)) => Content(concat(a, b)), (Commands(a), Commands(b)) => Commands(concat(a, b)), (a, b) => { - error!(@ctx.f, span, "cannot add {} and {}", a.name(), b.name()); + error!(@ctx.f, span, "cannot add {} and {}", a.ty(), b.ty()); Value::Error } }, @@ -151,7 +181,7 @@ impl ExprBinary { (Linear(a), Linear(b)) => Linear(a - b), (a, b) => { - error!(@ctx.f, span, "cannot subtract {1} from {0}", a.name(), b.name()); + error!(@ctx.f, span, "cannot subtract {1} from {0}", a.ty(), b.ty()); Value::Error } }, @@ -182,7 +212,7 @@ impl ExprBinary { (Str(a), Int(b)) => Str(a.repeat(b.max(0) as usize)), (a, b) => { - error!(@ctx.f, span, "cannot multiply {} with {}", a.name(), b.name()); + error!(@ctx.f, span, "cannot multiply {} with {}", a.ty(), b.ty()); Value::Error } }, @@ -203,7 +233,7 @@ impl ExprBinary { (Linear(a), Float(b)) => Linear(a / b), (a, b) => { - error!(@ctx.f, span, "cannot divide {} by {}", a.name(), b.name()); + error!(@ctx.f, span, "cannot divide {} by {}", a.ty(), b.ty()); Value::Error } }, @@ -232,32 +262,3 @@ pub enum BinOp { /// The division operator: `/`. Div, } - -/// An invocation of a function: `[foo: ...]`, `foo(...)`. -#[derive(Debug, Clone, PartialEq)] -pub struct ExprCall { - /// The name of the function. - pub name: Spanned, - /// The arguments to the function. - pub args: LitDict, -} - -impl ExprCall { - /// Evaluate the call expression to a value. - pub async fn eval(&self, ctx: &mut LayoutContext) -> Value { - let name = &self.name.v; - let span = self.name.span; - let args = self.args.eval(ctx).await; - - if let Some(func) = ctx.state.scope.func(name) { - ctx.f.decorations.push(Decoration::Resolved.span_with(span)); - (func.clone())(args, ctx).await - } else { - if !name.is_empty() { - error!(@ctx.f, span, "unknown function"); - ctx.f.decorations.push(Decoration::Unresolved.span_with(span)); - } - Value::Dict(args) - } - } -} diff --git a/src/syntax/ast/lit.rs b/src/syntax/ast/lit.rs index acc3aa0bc..414d54900 100644 --- a/src/syntax/ast/lit.rs +++ b/src/syntax/ast/lit.rs @@ -1,10 +1,10 @@ //! Literals. +use super::*; use crate::color::RgbaColor; -use crate::eval::{DictKey, DictValue, SpannedEntry, Value}; +use crate::eval::{DictKey, SpannedEntry, Value, ValueDict}; use crate::layout::LayoutContext; use crate::length::Length; -use crate::syntax::{Expr, Ident, SpanWith, Spanned, SynTree}; use crate::DynFuture; /// A literal. @@ -41,16 +41,16 @@ impl Lit { /// Evaluate the dictionary literal to a dictionary value. pub async fn eval(&self, ctx: &mut LayoutContext) -> Value { match *self { - Lit::Ident(ref i) => Value::Ident(i.clone()), - Lit::Bool(b) => Value::Bool(b), - Lit::Int(i) => Value::Int(i), - Lit::Float(f) => Value::Float(f), - Lit::Length(l) => Value::Length(l.as_raw()), - Lit::Percent(p) => Value::Relative(p / 100.0), - Lit::Color(c) => Value::Color(c), - Lit::Str(ref s) => Value::Str(s.clone()), - Lit::Dict(ref d) => Value::Dict(d.eval(ctx).await), - Lit::Content(ref c) => Value::Tree(c.clone()), + Lit::Ident(ref v) => Value::Ident(v.clone()), + Lit::Bool(v) => Value::Bool(v), + Lit::Int(v) => Value::Int(v), + Lit::Float(v) => Value::Float(v), + Lit::Length(v) => Value::Length(v.as_raw()), + Lit::Percent(v) => Value::Relative(v / 100.0), + Lit::Color(v) => Value::Color(v), + Lit::Str(ref v) => Value::Str(v.clone()), + Lit::Dict(ref v) => Value::Dict(v.eval(ctx).await), + Lit::Content(ref v) => Value::Content(v.clone()), } } } @@ -66,9 +66,9 @@ impl LitDict { } /// Evaluate the dictionary literal to a dictionary value. - pub fn eval<'a>(&'a self, ctx: &'a mut LayoutContext) -> DynFuture<'a, DictValue> { + pub fn eval<'a>(&'a self, ctx: &'a mut LayoutContext) -> DynFuture<'a, ValueDict> { Box::pin(async move { - let mut dict = DictValue::new(); + let mut dict = ValueDict::new(); for entry in &self.0 { let val = entry.expr.v.eval(ctx).await; @@ -76,7 +76,7 @@ impl LitDict { if let Some(key) = &entry.key { dict.insert(&key.v, SpannedEntry::new(key.span, spanned)); } else { - dict.push(SpannedEntry::val(spanned)); + dict.push(SpannedEntry::value(spanned)); } } diff --git a/src/syntax/ast/mod.rs b/src/syntax/ast/mod.rs index 56ae41342..df0fbc233 100644 --- a/src/syntax/ast/mod.rs +++ b/src/syntax/ast/mod.rs @@ -7,3 +7,5 @@ mod tree; pub use expr::*; pub use lit::*; pub use tree::*; + +use super::*; diff --git a/src/syntax/ast/tree.rs b/src/syntax/ast/tree.rs index c5dc4c65b..5723710dc 100644 --- a/src/syntax/ast/tree.rs +++ b/src/syntax/ast/tree.rs @@ -1,6 +1,6 @@ //! The syntax tree. -use crate::syntax::{Expr, Ident, SpanVec, Spanned}; +use super::*; /// A collection of nodes which form a tree together with the nodes' children. pub type SynTree = SpanVec;