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::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()
}
}

View File

@ -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),
}

View File

@ -222,7 +222,7 @@ fn bracket_body(p: &mut Parser) -> Tree {
fn block(p: &mut Parser) -> Option<Expr> {
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();
}

View File

@ -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<Expr>),
Group(ExprGroup),
/// A block expression: `{1 + 2}`.
Block(Box<Expr>),
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<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(...)`.
#[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<Expr>;
/// A grouped expression: `(1 + 2)`.
pub type ExprGroup = Box<Spanned<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;
/// A block expression: `{1 + 2}`.
pub type ExprBlock = Box<Spanned<Expr>>;
/// A let expression: `let x = 1`.
#[derive(Debug, Clone, PartialEq)]

View File

@ -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

View File

@ -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]

View File

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

View File

@ -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.