Optimize memory sizes

This commit is contained in:
Laurenz 2021-08-13 17:44:21 +02:00
parent 6a3385e4e7
commit f6814b7732
9 changed files with 233 additions and 203 deletions

View File

@ -177,6 +177,33 @@ impl Eval for Expr {
type Output = Value; type Output = Value;
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> { fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
match self {
Self::Ident(v) => v.eval(ctx),
Self::Lit(v) => v.eval(ctx),
Self::Array(v) => v.eval(ctx).map(Value::Array),
Self::Dict(v) => v.eval(ctx).map(Value::Dict),
Self::Template(v) => v.eval(ctx).map(Value::Template),
Self::Group(v) => v.eval(ctx),
Self::Block(v) => v.eval(ctx),
Self::Call(v) => v.eval(ctx),
Self::Closure(v) => v.eval(ctx),
Self::With(v) => v.eval(ctx),
Self::Unary(v) => v.eval(ctx),
Self::Binary(v) => v.eval(ctx),
Self::Let(v) => v.eval(ctx),
Self::If(v) => v.eval(ctx),
Self::While(v) => v.eval(ctx),
Self::For(v) => v.eval(ctx),
Self::Import(v) => v.eval(ctx),
Self::Include(v) => v.eval(ctx),
}
}
}
impl Eval for Lit {
type Output = Value;
fn eval(&self, _: &mut EvalContext) -> TypResult<Self::Output> {
Ok(match *self { Ok(match *self {
Self::None(_) => Value::None, Self::None(_) => Value::None,
Self::Auto(_) => Value::Auto, Self::Auto(_) => Value::Auto,
@ -188,23 +215,6 @@ impl Eval for Expr {
Self::Percent(_, v) => Value::Relative(Relative::new(v / 100.0)), Self::Percent(_, v) => Value::Relative(Relative::new(v / 100.0)),
Self::Fractional(_, v) => Value::Fractional(Fractional::new(v)), Self::Fractional(_, v) => Value::Fractional(Fractional::new(v)),
Self::Str(_, ref v) => Value::Str(v.clone()), Self::Str(_, ref v) => Value::Str(v.clone()),
Self::Ident(ref v) => v.eval(ctx)?,
Self::Array(ref v) => Value::Array(v.eval(ctx)?),
Self::Dict(ref v) => Value::Dict(v.eval(ctx)?),
Self::Template(ref v) => Value::Template(v.eval(ctx)?),
Self::Group(ref v) => v.eval(ctx)?,
Self::Block(ref v) => v.eval(ctx)?,
Self::Call(ref v) => v.eval(ctx)?,
Self::Closure(ref v) => v.eval(ctx)?,
Self::With(ref v) => v.eval(ctx)?,
Self::Unary(ref v) => v.eval(ctx)?,
Self::Binary(ref v) => v.eval(ctx)?,
Self::Let(ref v) => v.eval(ctx)?,
Self::If(ref v) => v.eval(ctx)?,
Self::While(ref v) => v.eval(ctx)?,
Self::For(ref v) => v.eval(ctx)?,
Self::Import(ref v) => v.eval(ctx)?,
Self::Include(ref v) => v.eval(ctx)?,
}) })
} }
} }
@ -674,8 +684,8 @@ impl Walk for SyntaxTree {
impl Walk for SyntaxNode { impl Walk for SyntaxNode {
fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> { fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> {
match self { match self {
Self::Text(_) => {}
Self::Space => {} Self::Space => {}
Self::Text(_) => {}
Self::Linebreak(_) => {} Self::Linebreak(_) => {}
Self::Parbreak(_) => {} Self::Parbreak(_) => {}
Self::Strong(_) => {} Self::Strong(_) => {}

View File

@ -52,8 +52,8 @@ impl ExecWithMap for SyntaxTree {
impl ExecWithMap for SyntaxNode { impl ExecWithMap for SyntaxNode {
fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap) { fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap) {
match self { match self {
Self::Text(text) => ctx.push_text(text),
Self::Space => ctx.push_word_space(), Self::Space => ctx.push_word_space(),
Self::Text(text) => ctx.push_text(text),
Self::Linebreak(_) => ctx.linebreak(), Self::Linebreak(_) => ctx.linebreak(),
Self::Parbreak(_) => ctx.parbreak(), Self::Parbreak(_) => ctx.parbreak(),
Self::Strong(_) => ctx.state.font_mut().strong ^= true, Self::Strong(_) => ctx.state.font_mut().strong ^= true,

View File

@ -5,7 +5,7 @@ use super::*;
/// A relative length. /// A relative length.
/// ///
/// _Note_: `50%` is represented as `0.5` here, but stored as `50.0` in the /// _Note_: `50%` is represented as `0.5` here, but stored as `50.0` in the
/// corresponding [literal](crate::syntax::Expr::Percent). /// corresponding [literal](crate::syntax::Lit::Percent).
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Relative(N64); pub struct Relative(N64);

View File

@ -65,10 +65,12 @@ where
if call.wide { if call.wide {
let start = p.next_start(); let start = p.next_start();
let tree = tree_while(p, true, f); let tree = tree_while(p, true, f);
call.args.items.push(CallArg::Pos(Expr::Template(TemplateExpr { call.args.items.push(CallArg::Pos(Expr::Template(Box::new(
span: p.span_from(start), TemplateExpr {
tree: Rc::new(tree), span: p.span_from(start),
}))); tree: Rc::new(tree),
},
))));
} }
} }
@ -181,7 +183,7 @@ fn raw(p: &mut Parser, token: RawToken) -> SyntaxNode {
if !token.terminated { if !token.terminated {
p.error(span.end, "expected backtick(s)"); p.error(span.end, "expected backtick(s)");
} }
SyntaxNode::Raw(raw) SyntaxNode::Raw(Box::new(raw))
} }
/// Parse a heading. /// Parse a heading.
@ -201,7 +203,11 @@ fn heading(p: &mut Parser) -> SyntaxNode {
} }
let body = tree_indented(p, column); let body = tree_indented(p, column);
SyntaxNode::Heading(HeadingNode { span: p.span_from(start), level, body }) SyntaxNode::Heading(Box::new(HeadingNode {
span: p.span_from(start),
level,
body,
}))
} }
/// Parse a single list item. /// Parse a single list item.
@ -210,7 +216,7 @@ fn list_item(p: &mut Parser) -> SyntaxNode {
let column = p.column(start); let column = p.column(start);
p.eat_assert(Token::Hyph); p.eat_assert(Token::Hyph);
let body = tree_indented(p, column); let body = tree_indented(p, column);
SyntaxNode::List(ListItem { span: p.span_from(start), body }) SyntaxNode::List(Box::new(ListItem { span: p.span_from(start), body }))
} }
/// Parse a single enum item. /// Parse a single enum item.
@ -219,7 +225,11 @@ fn enum_item(p: &mut Parser, number: Option<usize>) -> SyntaxNode {
let column = p.column(start); let column = p.column(start);
p.eat_assert(Token::Numbering(number)); p.eat_assert(Token::Numbering(number));
let body = tree_indented(p, column); let body = tree_indented(p, column);
SyntaxNode::Enum(EnumItem { span: p.span_from(start), number, body }) SyntaxNode::Enum(Box::new(EnumItem {
span: p.span_from(start),
number,
body,
}))
} }
/// Parse an expression. /// Parse an expression.
@ -239,8 +249,8 @@ fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) -> Option<Expr> {
let mut lhs = match p.eat_map(UnOp::from_token) { let mut lhs = match p.eat_map(UnOp::from_token) {
Some(op) => { Some(op) => {
let prec = op.precedence(); let prec = op.precedence();
let expr = Box::new(expr_with(p, atomic, prec)?); let expr = expr_with(p, atomic, prec)?;
Expr::Unary(UnaryExpr { span: p.span_from(start), op, expr }) Expr::Unary(Box::new(UnaryExpr { span: p.span_from(start), op, expr }))
} }
None => primary(p, atomic)?, None => primary(p, atomic)?,
}; };
@ -281,12 +291,12 @@ fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) -> Option<Expr> {
} }
let rhs = match expr_with(p, atomic, prec) { let rhs = match expr_with(p, atomic, prec) {
Some(rhs) => Box::new(rhs), Some(rhs) => rhs,
None => break, None => break,
}; };
let span = lhs.span().join(rhs.span()); let span = lhs.span().join(rhs.span());
lhs = Expr::Binary(BinaryExpr { span, lhs: Box::new(lhs), op, rhs }); lhs = Expr::Binary(Box::new(BinaryExpr { span, lhs, op, rhs }));
} }
Some(lhs) Some(lhs)
@ -309,14 +319,14 @@ fn primary(p: &mut Parser, atomic: bool) -> Option<Expr> {
// Arrow means this is a closure's lone parameter. // Arrow means this is a closure's lone parameter.
Some(if !atomic && p.eat_if(Token::Arrow) { Some(if !atomic && p.eat_if(Token::Arrow) {
let body = expr(p)?; let body = expr(p)?;
Expr::Closure(ClosureExpr { Expr::Closure(Box::new(ClosureExpr {
span: ident.span.join(body.span()), span: ident.span.join(body.span()),
name: None, name: None,
params: vec![ClosureParam::Pos(ident)], params: vec![ClosureParam::Pos(ident)],
body: Rc::new(body), body: Rc::new(body),
}) }))
} else { } else {
Expr::Ident(ident) Expr::Ident(Box::new(ident))
}) })
} }
@ -344,18 +354,18 @@ fn primary(p: &mut Parser, atomic: bool) -> Option<Expr> {
/// Parse a literal. /// Parse a literal.
fn literal(p: &mut Parser) -> Option<Expr> { fn literal(p: &mut Parser) -> Option<Expr> {
let span = p.peek_span(); let span = p.peek_span();
let expr = match p.peek()? { let lit = match p.peek()? {
// Basic values. // Basic values.
Token::None => Expr::None(span), Token::None => Lit::None(span),
Token::Auto => Expr::Auto(span), Token::Auto => Lit::Auto(span),
Token::Bool(b) => Expr::Bool(span, b), Token::Bool(b) => Lit::Bool(span, b),
Token::Int(i) => Expr::Int(span, i), Token::Int(i) => Lit::Int(span, i),
Token::Float(f) => Expr::Float(span, f), Token::Float(f) => Lit::Float(span, f),
Token::Length(val, unit) => Expr::Length(span, val, unit), Token::Length(val, unit) => Lit::Length(span, val, unit),
Token::Angle(val, unit) => Expr::Angle(span, val, unit), Token::Angle(val, unit) => Lit::Angle(span, val, unit),
Token::Percent(p) => Expr::Percent(span, p), Token::Percent(p) => Lit::Percent(span, p),
Token::Fraction(p) => Expr::Fractional(span, p), Token::Fraction(p) => Lit::Fractional(span, p),
Token::Str(token) => Expr::Str(span, { Token::Str(token) => Lit::Str(span, {
if !token.terminated { if !token.terminated {
p.expected_at(span.end, "quote"); p.expected_at(span.end, "quote");
} }
@ -364,7 +374,7 @@ fn literal(p: &mut Parser) -> Option<Expr> {
_ => return None, _ => return None,
}; };
p.eat(); p.eat();
Some(expr) Some(Expr::Lit(Box::new(lit)))
} }
/// Parse something that starts with a parenthesis, which can be either of: /// Parse something that starts with a parenthesis, which can be either of:
@ -387,21 +397,19 @@ fn parenthesized(p: &mut Parser) -> Option<Expr> {
if p.eat_if(Token::Arrow) { if p.eat_if(Token::Arrow) {
let params = params(p, items); let params = params(p, items);
let body = expr(p)?; let body = expr(p)?;
return Some(Expr::Closure(ClosureExpr { return Some(Expr::Closure(Box::new(ClosureExpr {
span: span.join(body.span()), span: span.join(body.span()),
name: None, name: None,
params, params,
body: Rc::new(body), body: Rc::new(body),
})); })));
} }
// Find out which kind of collection this is. // Find out which kind of collection this is.
Some(match items.as_slice() { Some(match items.as_slice() {
[] => array(p, items, span), [] => array(p, items, span),
[CallArg::Pos(_)] if !has_comma => match items.into_iter().next() { [CallArg::Pos(_)] if !has_comma => match items.into_iter().next() {
Some(CallArg::Pos(expr)) => { Some(CallArg::Pos(expr)) => Expr::Group(Box::new(GroupExpr { span, expr })),
Expr::Group(GroupExpr { span, expr: Box::new(expr) })
}
_ => unreachable!(), _ => unreachable!(),
}, },
[CallArg::Pos(_), ..] => array(p, items, span), [CallArg::Pos(_), ..] => array(p, items, span),
@ -454,7 +462,7 @@ fn item(p: &mut Parser) -> Option<CallArg> {
let first = expr(p)?; let first = expr(p)?;
if p.eat_if(Token::Colon) { if p.eat_if(Token::Colon) {
if let Expr::Ident(name) = first { if let Expr::Ident(name) = first {
Some(CallArg::Named(Named { name, expr: expr(p)? })) Some(CallArg::Named(Named { name: *name, expr: expr(p)? }))
} else { } else {
p.error(first.span(), "expected identifier"); p.error(first.span(), "expected identifier");
expr(p); expr(p);
@ -479,7 +487,7 @@ fn array(p: &mut Parser, items: Vec<CallArg>, span: Span) -> Expr {
None None
} }
}); });
Expr::Array(ArrayExpr { span, items: iter.collect() }) Expr::Array(Box::new(ArrayExpr { span, items: iter.collect() }))
} }
/// Convert a collection into a dictionary, producing errors for anything other /// Convert a collection into a dictionary, producing errors for anything other
@ -496,16 +504,16 @@ fn dict(p: &mut Parser, items: Vec<CallArg>, span: Span) -> Expr {
None None
} }
}); });
Expr::Dict(DictExpr { span, items: iter.collect() }) Expr::Dict(Box::new(DictExpr { span, items: iter.collect() }))
} }
/// Convert a collection into a list of parameters, producing errors for /// Convert a collection into a list of parameters, producing errors for
/// anything other than identifiers, spread operations and named pairs. /// anything other than identifiers, spread operations and named pairs.
fn params(p: &mut Parser, items: Vec<CallArg>) -> Vec<ClosureParam> { fn params(p: &mut Parser, items: Vec<CallArg>) -> Vec<ClosureParam> {
let iter = items.into_iter().filter_map(|item| match item { let iter = items.into_iter().filter_map(|item| match item {
CallArg::Pos(Expr::Ident(ident)) => Some(ClosureParam::Pos(ident)), CallArg::Pos(Expr::Ident(ident)) => Some(ClosureParam::Pos(*ident)),
CallArg::Named(named) => Some(ClosureParam::Named(named)), CallArg::Named(named) => Some(ClosureParam::Named(named)),
CallArg::Spread(Expr::Ident(ident)) => Some(ClosureParam::Sink(ident)), CallArg::Spread(Expr::Ident(ident)) => Some(ClosureParam::Sink(*ident)),
_ => { _ => {
p.error(item.span(), "expected identifier"); p.error(item.span(), "expected identifier");
None None
@ -518,7 +526,7 @@ fn params(p: &mut Parser, items: Vec<CallArg>) -> Vec<ClosureParam> {
/// anything other than identifiers. /// anything other than identifiers.
fn idents(p: &mut Parser, items: Vec<CallArg>) -> Vec<Ident> { fn idents(p: &mut Parser, items: Vec<CallArg>) -> Vec<Ident> {
let iter = items.into_iter().filter_map(|item| match item { let iter = items.into_iter().filter_map(|item| match item {
CallArg::Pos(Expr::Ident(id)) => Some(id), CallArg::Pos(Expr::Ident(ident)) => Some(*ident),
_ => { _ => {
p.error(item.span(), "expected identifier"); p.error(item.span(), "expected identifier");
None None
@ -532,7 +540,7 @@ fn template(p: &mut Parser) -> Expr {
p.start_group(Group::Bracket, TokenMode::Markup); p.start_group(Group::Bracket, TokenMode::Markup);
let tree = Rc::new(tree(p)); let tree = Rc::new(tree(p));
let span = p.end_group(); let span = p.end_group();
Expr::Template(TemplateExpr { span, tree }) Expr::Template(Box::new(TemplateExpr { span, tree }))
} }
/// Parse a block expression: `{...}`. /// Parse a block expression: `{...}`.
@ -553,7 +561,7 @@ fn block(p: &mut Parser, scoping: bool) -> Expr {
p.eat_while(|t| matches!(t, Token::Space(_))); p.eat_while(|t| matches!(t, Token::Space(_)));
} }
let span = p.end_group(); let span = p.end_group();
Expr::Block(BlockExpr { span, exprs, scoping }) Expr::Block(Box::new(BlockExpr { span, exprs, scoping }))
} }
/// Parse a function call. /// Parse a function call.
@ -582,12 +590,12 @@ fn call(p: &mut Parser, callee: Expr) -> Option<Expr> {
args.items.push(CallArg::Pos(body)); args.items.push(CallArg::Pos(body));
} }
Some(Expr::Call(CallExpr { Some(Expr::Call(Box::new(CallExpr {
span: p.span_from(callee.span().start), span: p.span_from(callee.span().start),
callee: Box::new(callee), callee,
wide, wide,
args, args,
})) })))
} }
/// Parse the arguments to a function call. /// Parse the arguments to a function call.
@ -601,11 +609,11 @@ fn args(p: &mut Parser) -> CallArgs {
/// Parse a with expression. /// Parse a with expression.
fn with_expr(p: &mut Parser, callee: Expr) -> Option<Expr> { fn with_expr(p: &mut Parser, callee: Expr) -> Option<Expr> {
if p.peek() == Some(Token::LeftParen) { if p.peek() == Some(Token::LeftParen) {
Some(Expr::With(WithExpr { Some(Expr::With(Box::new(WithExpr {
span: p.span_from(callee.span().start), span: p.span_from(callee.span().start),
callee: Box::new(callee), callee,
args: args(p), args: args(p),
})) })))
} else { } else {
p.expected("argument list"); p.expected("argument list");
None None
@ -622,7 +630,7 @@ fn let_expr(p: &mut Parser) -> Option<Expr> {
let mut init = None; let mut init = None;
if p.eat_if(Token::With) { if p.eat_if(Token::With) {
init = with_expr(p, Expr::Ident(binding.clone())); init = with_expr(p, Expr::Ident(Box::new(binding.clone())));
} else { } else {
// If a parenthesis follows, this is a function definition. // If a parenthesis follows, this is a function definition.
let mut maybe_params = None; let mut maybe_params = None;
@ -643,20 +651,20 @@ fn let_expr(p: &mut Parser) -> Option<Expr> {
// Rewrite into a closure expression if it's a function definition. // Rewrite into a closure expression if it's a function definition.
if let Some(params) = maybe_params { if let Some(params) = maybe_params {
let body = init?; let body = init?;
init = Some(Expr::Closure(ClosureExpr { init = Some(Expr::Closure(Box::new(ClosureExpr {
span: binding.span.join(body.span()), span: binding.span.join(body.span()),
name: Some(binding.clone()), name: Some(binding.clone()),
params, params,
body: Rc::new(body), body: Rc::new(body),
})); })));
} }
} }
let_expr = Some(Expr::Let(LetExpr { let_expr = Some(Expr::Let(Box::new(LetExpr {
span: p.span_from(start), span: p.span_from(start),
binding, binding,
init: init.map(Box::new), init,
})); })));
} }
let_expr let_expr
@ -680,12 +688,12 @@ fn if_expr(p: &mut Parser) -> Option<Expr> {
else_body = body(p); else_body = body(p);
} }
if_expr = Some(Expr::If(IfExpr { if_expr = Some(Expr::If(Box::new(IfExpr {
span: p.span_from(start), span: p.span_from(start),
condition: Box::new(condition), condition,
if_body: Box::new(if_body), if_body,
else_body: else_body.map(Box::new), else_body,
})); })));
} }
} }
@ -700,11 +708,11 @@ fn while_expr(p: &mut Parser) -> Option<Expr> {
let mut while_expr = None; let mut while_expr = None;
if let Some(condition) = expr(p) { if let Some(condition) = expr(p) {
if let Some(body) = body(p) { if let Some(body) = body(p) {
while_expr = Some(Expr::While(WhileExpr { while_expr = Some(Expr::While(Box::new(WhileExpr {
span: p.span_from(start), span: p.span_from(start),
condition: Box::new(condition), condition,
body: Box::new(body), body,
})); })));
} }
} }
@ -721,12 +729,12 @@ fn for_expr(p: &mut Parser) -> Option<Expr> {
if p.eat_expect(Token::In) { if p.eat_expect(Token::In) {
if let Some(iter) = expr(p) { if let Some(iter) = expr(p) {
if let Some(body) = body(p) { if let Some(body) = body(p) {
for_expr = Some(Expr::For(ForExpr { for_expr = Some(Expr::For(Box::new(ForExpr {
span: p.span_from(start), span: p.span_from(start),
pattern, pattern,
iter: Box::new(iter), iter,
body: Box::new(body), body,
})); })));
} }
} }
} }
@ -768,11 +776,11 @@ fn import_expr(p: &mut Parser) -> Option<Expr> {
let mut import_expr = None; let mut import_expr = None;
if p.eat_expect(Token::From) { if p.eat_expect(Token::From) {
if let Some(path) = expr(p) { if let Some(path) = expr(p) {
import_expr = Some(Expr::Import(ImportExpr { import_expr = Some(Expr::Import(Box::new(ImportExpr {
span: p.span_from(start), span: p.span_from(start),
imports, imports,
path: Box::new(path), path,
})); })));
} }
} }
@ -785,10 +793,7 @@ fn include_expr(p: &mut Parser) -> Option<Expr> {
p.eat_assert(Token::Include); p.eat_assert(Token::Include);
expr(p).map(|path| { expr(p).map(|path| {
Expr::Include(IncludeExpr { Expr::Include(Box::new(IncludeExpr { span: p.span_from(start), path }))
span: p.span_from(start),
path: Box::new(path),
})
}) })
} }

View File

@ -90,8 +90,8 @@ impl Pretty for SyntaxNode {
fn pretty(&self, p: &mut Printer) { fn pretty(&self, p: &mut Printer) {
match self { match self {
// TODO: Handle escaping. // TODO: Handle escaping.
Self::Text(text) => p.push_str(text),
Self::Space => p.push(' '), Self::Space => p.push(' '),
Self::Text(text) => p.push_str(text),
Self::Linebreak(_) => p.push_str(r"\"), Self::Linebreak(_) => p.push_str(r"\"),
Self::Parbreak(_) => p.push_str("\n\n"), Self::Parbreak(_) => p.push_str("\n\n"),
Self::Strong(_) => p.push('*'), Self::Strong(_) => p.push('*'),
@ -196,17 +196,8 @@ impl Pretty for EnumItem {
impl Pretty for Expr { impl Pretty for Expr {
fn pretty(&self, p: &mut Printer) { fn pretty(&self, p: &mut Printer) {
match self { match self {
Self::None(_) => p.push_str("none"),
Self::Auto(_) => p.push_str("auto"),
Self::Bool(_, v) => v.pretty(p),
Self::Int(_, v) => v.pretty(p),
Self::Float(_, v) => v.pretty(p),
Self::Length(_, v, u) => write!(p, "{}{}", v, u).unwrap(),
Self::Angle(_, v, u) => write!(p, "{}{}", v, u).unwrap(),
Self::Percent(_, v) => write!(p, "{}%", v).unwrap(),
Self::Fractional(_, v) => write!(p, "{}fr", v).unwrap(),
Self::Str(_, v) => v.pretty(p),
Self::Ident(v) => v.pretty(p), Self::Ident(v) => v.pretty(p),
Self::Lit(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) => v.pretty(p), Self::Template(v) => v.pretty(p),
@ -227,6 +218,23 @@ impl Pretty for Expr {
} }
} }
impl Pretty for Lit {
fn pretty(&self, p: &mut Printer) {
match self {
Self::None(_) => p.push_str("none"),
Self::Auto(_) => p.push_str("auto"),
Self::Bool(_, v) => v.pretty(p),
Self::Int(_, v) => v.pretty(p),
Self::Float(_, v) => v.pretty(p),
Self::Length(_, v, u) => write!(p, "{}{}", v, u).unwrap(),
Self::Angle(_, v, u) => write!(p, "{}{}", v, u).unwrap(),
Self::Percent(_, v) => write!(p, "{}%", v).unwrap(),
Self::Fractional(_, v) => write!(p, "{}fr", v).unwrap(),
Self::Str(_, v) => v.pretty(p),
}
}
}
impl Pretty for ArrayExpr { impl Pretty for ArrayExpr {
fn pretty(&self, p: &mut Printer) { fn pretty(&self, p: &mut Printer) {
p.push('('); p.push('(');

View File

@ -6,6 +6,87 @@ use crate::geom::{AngularUnit, LengthUnit};
/// An expression. /// An expression.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Expr { pub enum Expr {
/// An identifier: `left`.
Ident(Box<Ident>),
/// A literal: `1`, `true`, ...
Lit(Box<Lit>),
/// An array expression: `(1, "hi", 12cm)`.
Array(Box<ArrayExpr>),
/// A dictionary expression: `(thickness: 3pt, pattern: dashed)`.
Dict(Box<DictExpr>),
/// A template expression: `[*Hi* there!]`.
Template(Box<TemplateExpr>),
/// A grouped expression: `(1 + 2)`.
Group(Box<GroupExpr>),
/// A block expression: `{ let x = 1; x + 2 }`.
Block(Box<BlockExpr>),
/// A unary operation: `-x`.
Unary(Box<UnaryExpr>),
/// A binary operation: `a + b`.
Binary(Box<BinaryExpr>),
/// An invocation of a function: `f(x, y)`.
Call(Box<CallExpr>),
/// A closure expression: `(x, y) => z`.
Closure(Box<ClosureExpr>),
/// A with expression: `f with (x, y: 1)`.
With(Box<WithExpr>),
/// A let expression: `let x = 1`.
Let(Box<LetExpr>),
/// An if-else expression: `if x { y } else { z }`.
If(Box<IfExpr>),
/// A while loop expression: `while x { y }`.
While(Box<WhileExpr>),
/// A for loop expression: `for x in y { z }`.
For(Box<ForExpr>),
/// An import expression: `import a, b, c from "utils.typ"`.
Import(Box<ImportExpr>),
/// An include expression: `include "chapter1.typ"`.
Include(Box<IncludeExpr>),
}
impl Expr {
/// The source code location.
pub fn span(&self) -> Span {
match self {
Self::Ident(v) => v.span,
Self::Lit(v) => v.span(),
Self::Array(v) => v.span,
Self::Dict(v) => v.span,
Self::Template(v) => v.span,
Self::Group(v) => v.span,
Self::Block(v) => v.span,
Self::Unary(v) => v.span,
Self::Binary(v) => v.span,
Self::Call(v) => v.span,
Self::Closure(v) => v.span,
Self::With(v) => v.span,
Self::Let(v) => v.span,
Self::If(v) => v.span,
Self::While(v) => v.span,
Self::For(v) => v.span,
Self::Import(v) => v.span,
Self::Include(v) => v.span,
}
}
/// Whether the expression can be shortened in markup with a hashtag.
pub fn has_short_form(&self) -> bool {
matches!(self,
Self::Ident(_)
| Self::Call(_)
| Self::Let(_)
| Self::If(_)
| Self::While(_)
| Self::For(_)
| Self::Import(_)
| Self::Include(_)
)
}
}
/// A literal: `1`, `true`, ...
#[derive(Debug, Clone, PartialEq)]
pub enum Lit {
/// The none literal: `none`. /// The none literal: `none`.
None(Span), None(Span),
/// The auto literal: `auto`. /// The auto literal: `auto`.
@ -29,43 +110,9 @@ pub enum Expr {
Fractional(Span, f64), Fractional(Span, f64),
/// A string literal: `"hello!"`. /// A string literal: `"hello!"`.
Str(Span, EcoString), Str(Span, EcoString),
/// An identifier: `left`.
Ident(Ident),
/// An array expression: `(1, "hi", 12cm)`.
Array(ArrayExpr),
/// A dictionary expression: `(thickness: 3pt, pattern: dashed)`.
Dict(DictExpr),
/// A template expression: `[*Hi* there!]`.
Template(TemplateExpr),
/// A grouped expression: `(1 + 2)`.
Group(GroupExpr),
/// A block expression: `{ let x = 1; x + 2 }`.
Block(BlockExpr),
/// A unary operation: `-x`.
Unary(UnaryExpr),
/// A binary operation: `a + b`.
Binary(BinaryExpr),
/// An invocation of a function: `f(x, y)`.
Call(CallExpr),
/// A closure expression: `(x, y) => z`.
Closure(ClosureExpr),
/// A with expression: `f with (x, y: 1)`.
With(WithExpr),
/// A let expression: `let x = 1`.
Let(LetExpr),
/// An if-else expression: `if x { y } else { z }`.
If(IfExpr),
/// A while loop expression: `while x { y }`.
While(WhileExpr),
/// A for loop expression: `for x in y { z }`.
For(ForExpr),
/// An import expression: `import a, b, c from "utils.typ"`.
Import(ImportExpr),
/// An include expression: `include "chapter1.typ"`.
Include(IncludeExpr),
} }
impl Expr { impl Lit {
/// The source code location. /// The source code location.
pub fn span(&self) -> Span { pub fn span(&self) -> Span {
match *self { match *self {
@ -79,39 +126,8 @@ impl Expr {
Self::Percent(span, _) => span, Self::Percent(span, _) => span,
Self::Fractional(span, _) => span, Self::Fractional(span, _) => span,
Self::Str(span, _) => span, Self::Str(span, _) => span,
Self::Ident(ref v) => v.span,
Self::Array(ref v) => v.span,
Self::Dict(ref v) => v.span,
Self::Template(ref v) => v.span,
Self::Group(ref v) => v.span,
Self::Block(ref v) => v.span,
Self::Unary(ref v) => v.span,
Self::Binary(ref v) => v.span,
Self::Call(ref v) => v.span,
Self::Closure(ref v) => v.span,
Self::With(ref v) => v.span,
Self::Let(ref v) => v.span,
Self::If(ref v) => v.span,
Self::While(ref v) => v.span,
Self::For(ref v) => v.span,
Self::Import(ref v) => v.span,
Self::Include(ref v) => v.span,
} }
} }
/// Whether the expression can be shortened in markup with a hashtag.
pub fn has_short_form(&self) -> bool {
matches!(self,
Self::Ident(_)
| Self::Call(_)
| Self::Let(_)
| Self::If(_)
| Self::While(_)
| Self::For(_)
| Self::Import(_)
| Self::Include(_)
)
}
} }
/// An array expression: `(1, "hi", 12cm)`. /// An array expression: `(1, "hi", 12cm)`.
@ -163,7 +179,7 @@ pub struct GroupExpr {
/// The source code location. /// The source code location.
pub span: Span, pub span: Span,
/// The wrapped expression. /// The wrapped expression.
pub expr: Box<Expr>, pub expr: Expr,
} }
/// A block expression: `{ let x = 1; x + 2 }`. /// A block expression: `{ let x = 1; x + 2 }`.
@ -185,7 +201,7 @@ pub struct UnaryExpr {
/// The operator: `-`. /// The operator: `-`.
pub op: UnOp, pub op: UnOp,
/// The expression to operator on: `x`. /// The expression to operator on: `x`.
pub expr: Box<Expr>, pub expr: Expr,
} }
/// A unary operator. /// A unary operator.
@ -234,11 +250,11 @@ pub struct BinaryExpr {
/// The source code location. /// The source code location.
pub span: Span, pub span: Span,
/// The left-hand side of the operation: `a`. /// The left-hand side of the operation: `a`.
pub lhs: Box<Expr>, pub lhs: Expr,
/// The operator: `+`. /// The operator: `+`.
pub op: BinOp, pub op: BinOp,
/// The right-hand side of the operation: `b`. /// The right-hand side of the operation: `b`.
pub rhs: Box<Expr>, pub rhs: Expr,
} }
/// A binary operator. /// A binary operator.
@ -389,7 +405,7 @@ pub struct CallExpr {
/// The source code location. /// The source code location.
pub span: Span, pub span: Span,
/// The function to call. /// The function to call.
pub callee: Box<Expr>, pub callee: Expr,
/// Whether the call is wide, that is, capturing the template behind it. /// Whether the call is wide, that is, capturing the template behind it.
pub wide: bool, pub wide: bool,
/// The arguments to the function. /// The arguments to the function.
@ -475,7 +491,7 @@ pub struct WithExpr {
/// The source code location. /// The source code location.
pub span: Span, pub span: Span,
/// The function to apply the arguments to. /// The function to apply the arguments to.
pub callee: Box<Expr>, pub callee: Expr,
/// The arguments to apply to the function. /// The arguments to apply to the function.
pub args: CallArgs, pub args: CallArgs,
} }
@ -488,7 +504,7 @@ pub struct LetExpr {
/// The binding to assign to. /// The binding to assign to.
pub binding: Ident, pub binding: Ident,
/// The expression the binding is initialized with. /// The expression the binding is initialized with.
pub init: Option<Box<Expr>>, pub init: Option<Expr>,
} }
/// An import expression: `import a, b, c from "utils.typ"`. /// An import expression: `import a, b, c from "utils.typ"`.
@ -499,7 +515,7 @@ pub struct ImportExpr {
/// The items to be imported. /// The items to be imported.
pub imports: Imports, pub imports: Imports,
/// The location of the importable file. /// The location of the importable file.
pub path: Box<Expr>, pub path: Expr,
} }
/// The items that ought to be imported from a file. /// The items that ought to be imported from a file.
@ -517,7 +533,7 @@ pub struct IncludeExpr {
/// The source code location. /// The source code location.
pub span: Span, pub span: Span,
/// The location of the file to be included. /// The location of the file to be included.
pub path: Box<Expr>, pub path: Expr,
} }
/// An if-else expression: `if x { y } else { z }`. /// An if-else expression: `if x { y } else { z }`.
@ -526,11 +542,11 @@ pub struct IfExpr {
/// The source code location. /// The source code location.
pub span: Span, pub span: Span,
/// The condition which selects the body to evaluate. /// The condition which selects the body to evaluate.
pub condition: Box<Expr>, pub condition: Expr,
/// The expression to evaluate if the condition is true. /// The expression to evaluate if the condition is true.
pub if_body: Box<Expr>, pub if_body: Expr,
/// The expression to evaluate if the condition is false. /// The expression to evaluate if the condition is false.
pub else_body: Option<Box<Expr>>, pub else_body: Option<Expr>,
} }
/// A while loop expression: `while x { y }`. /// A while loop expression: `while x { y }`.
@ -539,9 +555,9 @@ pub struct WhileExpr {
/// The source code location. /// The source code location.
pub span: Span, pub span: Span,
/// The condition which selects whether to evaluate the body. /// The condition which selects whether to evaluate the body.
pub condition: Box<Expr>, pub condition: Expr,
/// The expression to evaluate while the condition is true. /// The expression to evaluate while the condition is true.
pub body: Box<Expr>, pub body: Expr,
} }
/// A for loop expression: `for x in y { z }`. /// A for loop expression: `for x in y { z }`.
@ -552,9 +568,9 @@ pub struct ForExpr {
/// The pattern to assign to. /// The pattern to assign to.
pub pattern: ForPattern, pub pattern: ForPattern,
/// The expression to iterate over. /// The expression to iterate over.
pub iter: Box<Expr>, pub iter: Expr,
/// The expression to evaluate for each iteration. /// The expression to evaluate for each iteration.
pub body: Box<Expr>, pub body: Expr,
} }
/// A pattern in a for loop. /// A pattern in a for loop.

View File

@ -3,10 +3,10 @@ use super::*;
/// A syntax node, encompassing a single logical entity of parsed source code. /// A syntax node, encompassing a single logical entity of parsed source code.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum SyntaxNode { pub enum SyntaxNode {
/// Plain text.
Text(EcoString),
/// Whitespace containing less than two newlines. /// Whitespace containing less than two newlines.
Space, Space,
/// Plain text.
Text(EcoString),
/// A forced line break: `\`. /// A forced line break: `\`.
Linebreak(Span), Linebreak(Span),
/// A paragraph break: Two or more newlines. /// A paragraph break: Two or more newlines.
@ -16,13 +16,13 @@ pub enum SyntaxNode {
/// Emphasized text was enabled / disabled: `_`. /// Emphasized text was enabled / disabled: `_`.
Emph(Span), Emph(Span),
/// A raw block with optional syntax highlighting: `` `...` ``. /// A raw block with optional syntax highlighting: `` `...` ``.
Raw(RawNode), Raw(Box<RawNode>),
/// A section heading: `= Introduction`. /// A section heading: `= Introduction`.
Heading(HeadingNode), Heading(Box<HeadingNode>),
/// An item in an unordered list: `- ...`. /// An item in an unordered list: `- ...`.
List(ListItem), List(Box<ListItem>),
/// An item in an enumeration (ordered list): `1. ...`. /// An item in an enumeration (ordered list): `1. ...`.
Enum(EnumItem), Enum(Box<EnumItem>),
/// An expression. /// An expression.
Expr(Expr), Expr(Expr),
} }

View File

@ -138,7 +138,7 @@ pub enum Token<'s> {
/// A percentage: `50%`. /// A percentage: `50%`.
/// ///
/// _Note_: `50%` is stored as `50.0` here, as in the corresponding /// _Note_: `50%` is stored as `50.0` here, as in the corresponding
/// [literal](super::Expr::Percent). /// [literal](super::Lit::Percent).
Percent(f64), Percent(f64),
/// A fraction unit: `3fr`. /// A fraction unit: `3fr`.
Fraction(f64), Fraction(f64),

View File

@ -86,8 +86,8 @@ impl_visitors! {
visit_node(v, node: SyntaxNode) { visit_node(v, node: SyntaxNode) {
match node { match node {
SyntaxNode::Text(_) => {}
SyntaxNode::Space => {} SyntaxNode::Space => {}
SyntaxNode::Text(_) => {}
SyntaxNode::Linebreak(_) => {} SyntaxNode::Linebreak(_) => {}
SyntaxNode::Parbreak(_) => {} SyntaxNode::Parbreak(_) => {}
SyntaxNode::Strong(_) => {} SyntaxNode::Strong(_) => {}
@ -114,17 +114,8 @@ impl_visitors! {
visit_expr(v, expr: Expr) { visit_expr(v, expr: Expr) {
match expr { match expr {
Expr::None(_) => {}
Expr::Auto(_) => {}
Expr::Bool(_, _) => {}
Expr::Int(_, _) => {}
Expr::Float(_, _) => {}
Expr::Length(_, _, _) => {}
Expr::Angle(_, _, _) => {}
Expr::Percent(_, _) => {}
Expr::Fractional(_, _) => {}
Expr::Str(_, _) => {}
Expr::Ident(_) => {} Expr::Ident(_) => {}
Expr::Lit(_) => {},
Expr::Array(e) => v.visit_array(e), Expr::Array(e) => v.visit_array(e),
Expr::Dict(e) => v.visit_dict(e), Expr::Dict(e) => v.visit_dict(e),
Expr::Template(e) => v.visit_template(e), Expr::Template(e) => v.visit_template(e),