Spans for group and block contents 📐

This commit is contained in:
Laurenz 2021-01-17 16:18:36 +01:00
parent 29be90bf95
commit dd246e5bc9
8 changed files with 86 additions and 77 deletions

View File

@ -172,14 +172,14 @@ impl Eval for Spanned<&Expr> {
Expr::Percent(v) => Value::Relative(Relative::new(v / 100.0)), Expr::Percent(v) => Value::Relative(Relative::new(v / 100.0)),
Expr::Color(v) => Value::Color(Color::Rgba(*v)), Expr::Color(v) => Value::Color(Color::Rgba(*v)),
Expr::Str(v) => Value::Str(v.clone()), 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::Array(v) => Value::Array(v.with_span(self.span).eval(ctx)),
Expr::Dict(v) => Value::Dict(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::Template(v) => Value::Template(v.clone()),
Expr::Group(v) => v.as_ref().with_span(self.span).eval(ctx), Expr::Call(v) => v.with_span(self.span).eval(ctx),
Expr::Block(v) => v.as_ref().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) => { Expr::Let(v) => {
let value = match &v.expr { let value = match &v.expr {
Some(expr) => expr.as_ref().eval(ctx), 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> { impl Eval for Spanned<&ExprUnary> {
type Output = Value; 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()
}
}

View File

@ -93,7 +93,7 @@ impl State {
fn into_expr(self) -> Expr { fn into_expr(self) -> Expr {
match self { match self {
Self::Unknown => Expr::Array(vec![]), 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::Array(array) => Expr::Array(array),
Self::Dict(dict) => Expr::Dict(dict), Self::Dict(dict) => Expr::Dict(dict),
} }

View File

@ -222,7 +222,7 @@ fn bracket_body(p: &mut Parser) -> Tree {
fn block(p: &mut Parser) -> Option<Expr> { fn block(p: &mut Parser) -> Option<Expr> {
p.push_mode(TokenMode::Code); p.push_mode(TokenMode::Code);
p.start_group(Group::Brace); p.start_group(Group::Brace);
let expr = expr(p); let expr = p.span_if(expr);
while !p.eof() { while !p.eof() {
p.diag_unexpected(); p.diag_unexpected();
} }

View File

@ -28,22 +28,22 @@ pub enum Expr {
Color(RgbaColor), Color(RgbaColor),
/// A string literal: `"hello!"`. /// A string literal: `"hello!"`.
Str(String), 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)`. /// An array expression: `(1, "hi", 12cm)`.
Array(ExprArray), Array(ExprArray),
/// A dictionary expression: `(color: #f79143, pattern: dashed)`. /// A dictionary expression: `(color: #f79143, pattern: dashed)`.
Dict(ExprDict), Dict(ExprDict),
/// A template expression: `[*Hi* there!]`. /// A template expression: `[*Hi* there!]`.
Template(ExprTemplate), 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)`. /// A grouped expression: `(1 + 2)`.
Group(Box<Expr>), Group(ExprGroup),
/// A block expression: `{1 + 2}`. /// A block expression: `{1 + 2}`.
Block(Box<Expr>), Block(ExprBlock),
/// A let expression: `let x = 1`. /// A let expression: `let x = 1`.
Let(ExprLet), Let(ExprLet),
} }
@ -61,9 +61,6 @@ impl Pretty for Expr {
Self::Percent(v) => write!(p, "{}%", v).unwrap(), Self::Percent(v) => write!(p, "{}%", v).unwrap(),
Self::Color(v) => write!(p, "{}", v).unwrap(), Self::Color(v) => write!(p, "{}", v).unwrap(),
Self::Str(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::Array(v) => v.pretty(p),
Self::Dict(v) => v.pretty(p), Self::Dict(v) => v.pretty(p),
Self::Template(v) => { Self::Template(v) => {
@ -71,14 +68,17 @@ impl Pretty for Expr {
v.pretty(p); v.pretty(p);
p.push_str("]"); p.push_str("]");
} }
Self::Unary(v) => v.pretty(p),
Self::Binary(v) => v.pretty(p),
Self::Call(v) => v.pretty(p),
Self::Group(v) => { Self::Group(v) => {
p.push_str("("); p.push_str("(");
v.pretty(p); v.v.pretty(p);
p.push_str(")"); p.push_str(")");
} }
Self::Block(v) => { Self::Block(v) => {
p.push_str("{"); p.push_str("{");
v.pretty(p); v.v.pretty(p);
p.push_str("}"); p.push_str("}");
} }
Self::Let(v) => v.pretty(p), Self::Let(v) => v.pretty(p),
@ -86,6 +86,38 @@ impl Pretty for Expr {
} }
} }
/// An array expression: `(1, "hi", 12cm)`.
pub type ExprArray = SpanVec<Expr>;
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<Named>;
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(...)`. /// An invocation of a function: `[foo ...]`, `foo(...)`.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct ExprCall { pub struct ExprCall {
@ -271,37 +303,11 @@ impl Pretty for BinOp {
} }
} }
/// An array expression: `(1, "hi", 12cm)`. /// A grouped expression: `(1 + 2)`.
pub type ExprArray = SpanVec<Expr>; pub type ExprGroup = Box<Spanned<Expr>>;
impl Pretty for ExprArray { /// A block expression: `{1 + 2}`.
fn pretty(&self, p: &mut Printer) { pub type ExprBlock = Box<Spanned<Expr>>;
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<Named>;
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 let expression: `let x = 1`. /// A let expression: `let x = 1`.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]

View File

@ -71,7 +71,7 @@
--- ---
// Ref: false // Ref: false
// Error: 2:2-2:3 a value of type string is not callable // Error: 2:2-2:3 a value of type string is not callable
#let x = "string"; #let x = "string"
[x] [x]
// Error: 1:2-1:3 expected function name, found hex value // Error: 1:2-1:3 expected function name, found hex value

View File

@ -1,7 +1,7 @@
// Ref: false // Ref: false
#let a = 2; #let a = 2
#let b = 4; #let b = 4
// Paren call. // Paren call.
[eq f(1), "f(1)"] [eq f(1), "f(1)"]
@ -30,6 +30,9 @@
[eq (2), 2] [eq (2), 2]
[eq (1+2)*3, 9] [eq (1+2)*3, 9]
// Error: 1:3-1:10 cannot add integer and string
{(1 + "2")}
// Confusion with floating-point literal. // Confusion with floating-point literal.
[eq 1e+2-1e-2, 99.99] [eq 1e+2-1e-2, 99.99]

View File

@ -5,7 +5,7 @@
[eq x, none] [eq x, none]
// Initialized with `1`. // Initialized with `1`.
#let y = 1; #let y = 1
[eq y, 1] [eq y, 1]
// Multiple bindings in one line. // Multiple bindings in one line.

View File

@ -1,15 +1,15 @@
// Test representation of values in the document. // Test representation of values in the document.
#let name = "Typst"; #let name = "Typst"
#let ke-bab = "Kebab!"; #let ke-bab = "Kebab!"
#let α = "Alpha"; #let α = "Alpha"
// Variables. // Variables.
{name} \ {name} \
{ke-bab} \ {ke-bab} \
{α} \ {α} \
// Error: 1:1-1:4 unknown variable // Error: 1:2-1:3 unknown variable
{_} {_}
// Literal values. // Literal values.