diff --git a/src/eval/mod.rs b/src/eval/mod.rs index efc77f69d..c7b87aefd 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -172,14 +172,14 @@ impl Eval for Spanned<&Expr> { Expr::Percent(v) => Value::Relative(Relative::new(v / 100.0)), Expr::Color(v) => Value::Color(Color::Rgba(*v)), Expr::Str(v) => Value::Str(v.clone()), - Expr::Call(v) => v.with_span(self.span).eval(ctx), - Expr::Unary(v) => v.with_span(self.span).eval(ctx), - Expr::Binary(v) => v.with_span(self.span).eval(ctx), Expr::Array(v) => Value::Array(v.with_span(self.span).eval(ctx)), Expr::Dict(v) => Value::Dict(v.with_span(self.span).eval(ctx)), Expr::Template(v) => Value::Template(v.clone()), - Expr::Group(v) => v.as_ref().with_span(self.span).eval(ctx), - Expr::Block(v) => v.as_ref().with_span(self.span).eval(ctx), + Expr::Call(v) => v.with_span(self.span).eval(ctx), + Expr::Unary(v) => v.with_span(self.span).eval(ctx), + Expr::Binary(v) => v.with_span(self.span).eval(ctx), + Expr::Group(v) => v.as_ref().eval(ctx), + Expr::Block(v) => v.as_ref().eval(ctx), Expr::Let(v) => { let value = match &v.expr { Some(expr) => expr.as_ref().eval(ctx), @@ -192,6 +192,25 @@ impl Eval for Spanned<&Expr> { } } +impl Eval for Spanned<&ExprArray> { + type Output = ValueArray; + + fn eval(self, ctx: &mut EvalContext) -> Self::Output { + self.v.iter().map(|expr| expr.as_ref().eval(ctx)).collect() + } +} + +impl Eval for Spanned<&ExprDict> { + type Output = ValueDict; + + 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() + } +} + impl Eval for Spanned<&ExprUnary> { type Output = Value; @@ -230,22 +249,3 @@ impl Eval for Spanned<&ExprBinary> { } } } - -impl Eval for Spanned<&ExprArray> { - type Output = ValueArray; - - fn eval(self, ctx: &mut EvalContext) -> Self::Output { - self.v.iter().map(|expr| expr.as_ref().eval(ctx)).collect() - } -} - -impl Eval for Spanned<&ExprDict> { - type Output = ValueDict; - - 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() - } -} diff --git a/src/parse/collection.rs b/src/parse/collection.rs index ca05b9985..9addcef09 100644 --- a/src/parse/collection.rs +++ b/src/parse/collection.rs @@ -93,7 +93,7 @@ impl State { fn into_expr(self) -> Expr { match self { Self::Unknown => Expr::Array(vec![]), - Self::Expr(expr) => Expr::Group(Box::new(expr.v)), + Self::Expr(expr) => Expr::Group(Box::new(expr)), Self::Array(array) => Expr::Array(array), Self::Dict(dict) => Expr::Dict(dict), } diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 7c92185d5..0a6563667 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -222,7 +222,7 @@ fn bracket_body(p: &mut Parser) -> Tree { fn block(p: &mut Parser) -> Option { p.push_mode(TokenMode::Code); p.start_group(Group::Brace); - let expr = expr(p); + let expr = p.span_if(expr); while !p.eof() { p.diag_unexpected(); } diff --git a/src/syntax/expr.rs b/src/syntax/expr.rs index 795339183..79713cf11 100644 --- a/src/syntax/expr.rs +++ b/src/syntax/expr.rs @@ -28,22 +28,22 @@ pub enum Expr { Color(RgbaColor), /// A string literal: `"hello!"`. Str(String), - /// 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 array expression: `(1, "hi", 12cm)`. Array(ExprArray), /// A dictionary expression: `(color: #f79143, pattern: dashed)`. Dict(ExprDict), /// A template expression: `[*Hi* there!]`. Template(ExprTemplate), + /// A unary operation: `-x`. + Unary(ExprUnary), + /// A binary operation: `a + b`, `a / b`. + Binary(ExprBinary), + /// An invocation of a function: `[foo ...]`, `foo(...)`. + Call(ExprCall), /// A grouped expression: `(1 + 2)`. - Group(Box), + Group(ExprGroup), /// A block expression: `{1 + 2}`. - Block(Box), + Block(ExprBlock), /// A let expression: `let x = 1`. Let(ExprLet), } @@ -61,9 +61,6 @@ impl Pretty for Expr { Self::Percent(v) => write!(p, "{}%", v).unwrap(), Self::Color(v) => write!(p, "{}", v).unwrap(), Self::Str(v) => write!(p, "{:?}", &v).unwrap(), - Self::Call(v) => v.pretty(p), - Self::Unary(v) => v.pretty(p), - Self::Binary(v) => v.pretty(p), Self::Array(v) => v.pretty(p), Self::Dict(v) => v.pretty(p), Self::Template(v) => { @@ -71,14 +68,17 @@ impl Pretty for Expr { v.pretty(p); p.push_str("]"); } + Self::Unary(v) => v.pretty(p), + Self::Binary(v) => v.pretty(p), + Self::Call(v) => v.pretty(p), Self::Group(v) => { p.push_str("("); - v.pretty(p); + v.v.pretty(p); p.push_str(")"); } Self::Block(v) => { p.push_str("{"); - v.pretty(p); + v.v.pretty(p); p.push_str("}"); } Self::Let(v) => v.pretty(p), @@ -86,6 +86,38 @@ impl Pretty for Expr { } } +/// An array expression: `(1, "hi", 12cm)`. +pub type ExprArray = SpanVec; + +impl Pretty for ExprArray { + fn pretty(&self, p: &mut Printer) { + p.push_str("("); + p.join(self, ", ", |item, p| item.v.pretty(p)); + if self.len() == 1 { + p.push_str(","); + } + p.push_str(")"); + } +} + +/// A dictionary expression: `(color: #f79143, pattern: dashed)`. +pub type ExprDict = Vec; + +impl Pretty for ExprDict { + fn pretty(&self, p: &mut Printer) { + p.push_str("("); + if self.is_empty() { + p.push_str(":"); + } else { + p.join(self, ", ", |named, p| named.pretty(p)); + } + p.push_str(")"); + } +} + +/// A template expression: `[*Hi* there!]`. +pub type ExprTemplate = Tree; + /// An invocation of a function: `[foo ...]`, `foo(...)`. #[derive(Debug, Clone, PartialEq)] pub struct ExprCall { @@ -271,37 +303,11 @@ impl Pretty for BinOp { } } -/// An array expression: `(1, "hi", 12cm)`. -pub type ExprArray = SpanVec; +/// A grouped expression: `(1 + 2)`. +pub type ExprGroup = Box>; -impl Pretty for ExprArray { - fn pretty(&self, p: &mut Printer) { - p.push_str("("); - p.join(self, ", ", |item, p| item.v.pretty(p)); - if self.len() == 1 { - p.push_str(","); - } - p.push_str(")"); - } -} - -/// A dictionary expression: `(color: #f79143, pattern: dashed)`. -pub type ExprDict = Vec; - -impl Pretty for ExprDict { - fn pretty(&self, p: &mut Printer) { - p.push_str("("); - if self.is_empty() { - p.push_str(":"); - } else { - p.join(self, ", ", |named, p| named.pretty(p)); - } - p.push_str(")"); - } -} - -/// A template expression: `[*Hi* there!]`. -pub type ExprTemplate = Tree; +/// A block expression: `{1 + 2}`. +pub type ExprBlock = Box>; /// A let expression: `let x = 1`. #[derive(Debug, Clone, PartialEq)] diff --git a/tests/lang/typ/bracket-call.typ b/tests/lang/typ/bracket-call.typ index 79667e610..7bbaeac18 100644 --- a/tests/lang/typ/bracket-call.typ +++ b/tests/lang/typ/bracket-call.typ @@ -71,7 +71,7 @@ --- // Ref: false // Error: 2:2-2:3 a value of type string is not callable -#let x = "string"; +#let x = "string" [x] // Error: 1:2-1:3 expected function name, found hex value diff --git a/tests/lang/typ/expressions.typ b/tests/lang/typ/expressions.typ index 74150c4bc..97aa8d812 100644 --- a/tests/lang/typ/expressions.typ +++ b/tests/lang/typ/expressions.typ @@ -1,7 +1,7 @@ // Ref: false -#let a = 2; -#let b = 4; +#let a = 2 +#let b = 4 // Paren call. [eq f(1), "f(1)"] @@ -30,6 +30,9 @@ [eq (2), 2] [eq (1+2)*3, 9] +// Error: 1:3-1:10 cannot add integer and string +{(1 + "2")} + // Confusion with floating-point literal. [eq 1e+2-1e-2, 99.99] diff --git a/tests/lang/typ/let.typ b/tests/lang/typ/let.typ index a966f2434..28fc6649b 100644 --- a/tests/lang/typ/let.typ +++ b/tests/lang/typ/let.typ @@ -5,7 +5,7 @@ [eq x, none] // Initialized with `1`. -#let y = 1; +#let y = 1 [eq y, 1] // Multiple bindings in one line. diff --git a/tests/lang/typ/values.typ b/tests/lang/typ/values.typ index 51d0bd17b..cab63044e 100644 --- a/tests/lang/typ/values.typ +++ b/tests/lang/typ/values.typ @@ -1,15 +1,15 @@ // Test representation of values in the document. -#let name = "Typst"; -#let ke-bab = "Kebab!"; -#let α = "Alpha"; +#let name = "Typst" +#let ke-bab = "Kebab!" +#let α = "Alpha" // Variables. {name} \ {ke-bab} \ {α} \ -// Error: 1:1-1:4 unknown variable +// Error: 1:2-1:3 unknown variable {_} // Literal values.