diff --git a/src/eval/capture.rs b/src/eval/capture.rs index fd6b01018..b27aceb72 100644 --- a/src/eval/capture.rs +++ b/src/eval/capture.rs @@ -49,6 +49,15 @@ impl<'a> CapturesVisitor<'a> { // through the expressions that contain them). Some(Expr::Ident(ident)) => self.capture(ident), + // Blocks and templates create a scope. + Some(Expr::Code(_) | Expr::Template(_)) => { + self.internal.enter(); + for child in node.children() { + self.visit(child); + } + self.internal.exit(); + } + // A closure contains parameter bindings, which are bound before the // body is evaluated. Care must be taken so that the default values // of named parameters cannot access previous parameter bindings. @@ -103,15 +112,6 @@ impl<'a> CapturesVisitor<'a> { } } - // Blocks and templates create a scope. - Some(Expr::Block(_) | Expr::Template(_)) => { - self.internal.enter(); - for child in node.children() { - self.visit(child); - } - self.internal.exit(); - } - // Everything else is traversed from left to right. _ => { for child in node.children() { diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 590b84633..6a918dbde 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -202,11 +202,11 @@ impl Eval for Expr { match self { Self::Lit(v) => v.eval(ctx, scp), Self::Ident(v) => v.eval(ctx, scp), + Self::Code(v) => v.eval(ctx, scp), + Self::Template(v) => v.eval(ctx, scp).map(Value::Template), Self::Array(v) => v.eval(ctx, scp).map(Value::Array), Self::Dict(v) => v.eval(ctx, scp).map(Value::Dict), - Self::Template(v) => v.eval(ctx, scp).map(Value::Template), Self::Group(v) => v.eval(ctx, scp), - Self::Block(v) => v.eval(ctx, scp), Self::Call(v) => v.eval(ctx, scp), Self::Closure(v) => v.eval(ctx, scp), Self::With(v) => v.eval(ctx, scp), @@ -260,25 +260,23 @@ impl Eval for Ident { } } -impl Eval for ArrayExpr { - type Output = Array; +impl Eval for CodeBlock { + type Output = Value; fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult { - self.items().map(|expr| expr.eval(ctx, scp)).collect() + scp.enter(); + + let mut output = Value::None; + for expr in self.exprs() { + output = join_result(output, expr.eval(ctx, scp), expr.span())?; + } + + scp.exit(); + Ok(output) } } -impl Eval for DictExpr { - type Output = Dict; - - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult { - self.items() - .map(|x| Ok((x.name().take(), x.expr().eval(ctx, scp)?))) - .collect() - } -} - -impl Eval for TemplateExpr { +impl Eval for TemplateBlock { type Output = Template; fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult { @@ -297,19 +295,21 @@ impl Eval for GroupExpr { } } -impl Eval for BlockExpr { - type Output = Value; +impl Eval for ArrayExpr { + type Output = Array; fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult { - scp.enter(); + self.items().map(|expr| expr.eval(ctx, scp)).collect() + } +} - let mut output = Value::None; - for expr in self.exprs() { - output = join_result(output, expr.eval(ctx, scp), expr.span())?; - } +impl Eval for DictExpr { + type Output = Dict; - scp.exit(); - Ok(output) + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult { + self.items() + .map(|x| Ok((x.name().take(), x.expr().eval(ctx, scp)?))) + .collect() } } diff --git a/src/eval/value.rs b/src/eval/value.rs index 009a1463a..7d41bff50 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -5,7 +5,7 @@ use std::hash::{Hash, Hasher}; use std::sync::Arc; use super::{ops, Args, Array, Class, Dict, Func, Layout, Template}; -use crate::diag::StrResult; +use crate::diag::{with_alternative, StrResult}; use crate::geom::{Angle, Color, Fractional, Length, Linear, Relative, RgbaColor}; use crate::syntax::Spanned; use crate::util::EcoString; @@ -533,16 +533,6 @@ impl Cast for Smart { } } -/// Transform `expected X, found Y` into `expected X or A, found Y`. -pub fn with_alternative(msg: String, alt: &str) -> String { - let mut parts = msg.split(", found "); - if let (Some(a), Some(b)) = (parts.next(), parts.next()) { - format!("{} or {}, found {}", a, alt, b) - } else { - msg - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/src/library/math/mod.rs b/src/library/math/mod.rs index 761b44801..c5b791171 100644 --- a/src/library/math/mod.rs +++ b/src/library/math/mod.rs @@ -1,3 +1,5 @@ +//! Mathematical formulas. + use crate::library::prelude::*; /// A mathematical formula. diff --git a/src/library/text/mod.rs b/src/library/text/mod.rs index 1ce3518ce..197971d02 100644 --- a/src/library/text/mod.rs +++ b/src/library/text/mod.rs @@ -1,4 +1,4 @@ -//! Text shaping and paragraph layout. +//! Text handling and paragraph layout. mod deco; mod link; diff --git a/src/parse/incremental.rs b/src/parse/incremental.rs index 4736845f5..759b3a68c 100644 --- a/src/parse/incremental.rs +++ b/src/parse/incremental.rs @@ -136,8 +136,8 @@ impl Reparser<'_> { let superseded_span = pos.offset .. pos.offset + prev_len; let func: Option = match child.kind() { - NodeKind::Template => Some(ReparseMode::Template), - NodeKind::Block => Some(ReparseMode::Block), + NodeKind::CodeBlock => Some(ReparseMode::Code), + NodeKind::TemplateBlock => Some(ReparseMode::Template), _ => None, }; @@ -211,7 +211,7 @@ impl Reparser<'_> { } let (newborns, terminated, amount) = match mode { - ReparseMode::Block => reparse_block( + ReparseMode::Code => reparse_block( &prefix, &self.src[newborn_span.start ..], newborn_span.len(), @@ -292,9 +292,9 @@ impl SearchState { /// Which reparse function to choose for a span of elements. #[derive(Clone, Copy, Debug, PartialEq)] enum ReparseMode { - /// Reparse a code block with its braces. - Block, - /// Reparse a template, including its square brackets. + /// Reparse a code block, including its braces. + Code, + /// Reparse a template block, including its square brackets. Template, /// Reparse elements of the markup. The variant carries whether the node is /// `at_start` and the minimum indent of the containing markup node. diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 11ce872f8..833a5b339 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -28,8 +28,57 @@ pub fn parse(src: &str) -> Arc { } } -/// Parse some markup without the topmost node. Returns `Some` if all of the -/// input was consumed. +/// Reparse a code block. +/// +/// Returns `Some` if all of the input was consumed. +pub fn reparse_block( + prefix: &str, + src: &str, + end_pos: usize, +) -> Option<(Vec, bool, usize)> { + let mut p = Parser::with_prefix(prefix, src, TokenMode::Code); + if !p.at(&NodeKind::LeftBrace) { + return None; + } + + block(&mut p); + + let (mut green, terminated) = p.consume()?; + let first = green.remove(0); + if first.len() != end_pos { + return None; + } + + Some((vec![first], terminated, 1)) +} + +/// Reparse a template literal. +/// +/// Returns `Some` if all of the input was consumed. +pub fn reparse_template( + prefix: &str, + src: &str, + end_pos: usize, +) -> Option<(Vec, bool, usize)> { + let mut p = Parser::with_prefix(prefix, src, TokenMode::Code); + if !p.at(&NodeKind::LeftBracket) { + return None; + } + + template(&mut p); + + let (mut green, terminated) = p.consume()?; + let first = green.remove(0); + if first.len() != end_pos { + return None; + } + + Some((vec![first], terminated, 1)) +} + +/// Reparse some markup elements without the topmost node. +/// +/// Returns `Some` if all of the input was consumed. pub fn reparse_markup_elements( prefix: &str, src: &str, @@ -100,50 +149,6 @@ pub fn reparse_markup_elements( Some((res, terminated, replaced)) } -/// Parse a template literal. Returns `Some` if all of the input was consumed. -pub fn reparse_template( - prefix: &str, - src: &str, - end_pos: usize, -) -> Option<(Vec, bool, usize)> { - let mut p = Parser::with_prefix(prefix, src, TokenMode::Code); - if !p.at(&NodeKind::LeftBracket) { - return None; - } - - template(&mut p); - - let (mut green, terminated) = p.consume()?; - let first = green.remove(0); - if first.len() != end_pos { - return None; - } - - Some((vec![first], terminated, 1)) -} - -/// Parse a code block. Returns `Some` if all of the input was consumed. -pub fn reparse_block( - prefix: &str, - src: &str, - end_pos: usize, -) -> Option<(Vec, bool, usize)> { - let mut p = Parser::with_prefix(prefix, src, TokenMode::Code); - if !p.at(&NodeKind::LeftBrace) { - return None; - } - - block(&mut p); - - let (mut green, terminated) = p.consume()?; - let first = green.remove(0); - if first.len() != end_pos { - return None; - } - - Some((vec![first], terminated, 1)) -} - /// Parse markup. /// /// If `at_start` is true, things like headings that may only appear at the @@ -201,9 +206,9 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) { // Text and markup. NodeKind::Text(_) + | NodeKind::NonBreakingSpace | NodeKind::EnDash | NodeKind::EmDash - | NodeKind::NonBreakingSpace | NodeKind::Linebreak | NodeKind::Raw(_) | NodeKind::Math(_) @@ -350,7 +355,7 @@ fn expr_prec(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult { p.eat(); let prec = op.precedence(); expr_prec(p, atomic, prec)?; - marker.end(p, NodeKind::Unary); + marker.end(p, NodeKind::UnaryExpr); } _ => primary(p, atomic)?, }; @@ -388,7 +393,7 @@ fn expr_prec(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult { Associativity::Right => {} } - marker.perform(p, NodeKind::Binary, |p| expr_prec(p, atomic, prec))?; + marker.perform(p, NodeKind::BinaryExpr, |p| expr_prec(p, atomic, prec))?; } Ok(()) @@ -410,7 +415,7 @@ fn primary(p: &mut Parser, atomic: bool) -> ParseResult { if !atomic && p.at(&NodeKind::Arrow) { marker.end(p, NodeKind::ClosureParams); p.eat_assert(&NodeKind::Arrow); - marker.perform(p, NodeKind::Closure, expr) + marker.perform(p, NodeKind::ClosureExpr, expr) } else { Ok(()) } @@ -418,14 +423,8 @@ fn primary(p: &mut Parser, atomic: bool) -> ParseResult { // Structures. Some(NodeKind::LeftParen) => parenthesized(p, atomic), - Some(NodeKind::LeftBracket) => { - template(p); - Ok(()) - } - Some(NodeKind::LeftBrace) => { - block(p); - Ok(()) - } + Some(NodeKind::LeftBrace) => Ok(block(p)), + Some(NodeKind::LeftBracket) => Ok(template(p)), // Keywords. Some(NodeKind::Let) => let_expr(p), @@ -478,6 +477,20 @@ fn literal(p: &mut Parser) -> bool { } } +/// Parse an identifier. +fn ident(p: &mut Parser) -> ParseResult { + match p.peek() { + Some(NodeKind::Ident(_)) => { + p.eat(); + Ok(()) + } + _ => { + p.expected_found("identifier"); + Err(ParseError) + } + } +} + /// Parse something that starts with a parenthesis, which can be either of: /// - Array literal /// - Dictionary literal @@ -501,12 +514,12 @@ fn parenthesized(p: &mut Parser, atomic: bool) -> ParseResult { if !atomic && p.at(&NodeKind::Arrow) { params(p, marker); p.eat_assert(&NodeKind::Arrow); - return marker.perform(p, NodeKind::Closure, expr); + return marker.perform(p, NodeKind::ClosureExpr, expr); } // Transform into the identified collection. match kind { - CollectionKind::Group => marker.end(p, NodeKind::Group), + CollectionKind::Group => marker.end(p, NodeKind::GroupExpr), CollectionKind::Positional => array(p, marker), CollectionKind::Named => dict(p, marker), } @@ -614,7 +627,7 @@ fn array(p: &mut Parser, marker: Marker) { NodeKind::Spread => Err("spreading is not allowed here"), _ => Ok(()), }); - marker.end(p, NodeKind::Array); + marker.end(p, NodeKind::ArrayExpr); } /// Convert a collection into a dictionary, producing errors for anything other @@ -626,7 +639,7 @@ fn dict(p: &mut Parser, marker: Marker) { NodeKind::Spread => Err("spreading is not allowed here"), _ => Err("expected named pair, found expression"), }); - marker.end(p, NodeKind::Dict); + marker.end(p, NodeKind::DictExpr); } /// Convert a collection into a list of parameters, producing errors for @@ -648,18 +661,9 @@ fn params(p: &mut Parser, marker: Marker) { marker.end(p, NodeKind::ClosureParams); } -// Parse a template block: `[...]`. -fn template(p: &mut Parser) { - p.perform(NodeKind::Template, |p| { - p.start_group(Group::Bracket); - markup(p, true); - p.end_group(); - }); -} - /// Parse a code block: `{...}`. fn block(p: &mut Parser) { - p.perform(NodeKind::Block, |p| { + p.perform(NodeKind::CodeBlock, |p| { p.start_group(Group::Brace); while !p.eof() { p.start_group(Group::Expr); @@ -675,9 +679,18 @@ fn block(p: &mut Parser) { }); } +// Parse a template block: `[...]`. +fn template(p: &mut Parser) { + p.perform(NodeKind::TemplateBlock, |p| { + p.start_group(Group::Bracket); + markup(p, true); + p.end_group(); + }); +} + /// Parse a function call. fn call(p: &mut Parser, callee: Marker) -> ParseResult { - callee.perform(p, NodeKind::Call, |p| args(p, true, true)) + callee.perform(p, NodeKind::CallExpr, |p| args(p, true, true)) } /// Parse the arguments to a function call. @@ -744,7 +757,7 @@ fn let_expr(p: &mut Parser) -> ParseResult { // Rewrite into a closure expression if it's a function definition. if has_params { - marker.end(p, NodeKind::Closure); + marker.end(p, NodeKind::ClosureExpr); } } @@ -770,7 +783,7 @@ fn show_expr(p: &mut Parser) -> ParseResult { p.expected_found("parameter list"); return Err(ParseError); } - p.perform(NodeKind::Closure, |p| { + p.perform(NodeKind::ClosureExpr, |p| { let marker = p.marker(); p.start_group(Group::Paren); collection(p); @@ -906,31 +919,16 @@ fn return_expr(p: &mut Parser) -> ParseResult { }) } -/// Parse an identifier. -fn ident(p: &mut Parser) -> ParseResult { - match p.peek() { - Some(NodeKind::Ident(_)) => { - p.eat(); - Ok(()) - } - _ => { - p.expected_found("identifier"); - Err(ParseError) - } - } -} - /// Parse a control flow body. fn body(p: &mut Parser) -> ParseResult { match p.peek() { - Some(NodeKind::LeftBracket) => template(p), - Some(NodeKind::LeftBrace) => block(p), + Some(NodeKind::LeftBracket) => Ok(template(p)), + Some(NodeKind::LeftBrace) => Ok(block(p)), _ => { p.expected("body"); - return Err(ParseError); + Err(ParseError) } } - Ok(()) } #[cfg(test)] diff --git a/src/parse/parser.rs b/src/parse/parser.rs index 123871a58..33cf489c1 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -229,13 +229,13 @@ impl<'s> Parser<'s> { self.groups.push(GroupEntry { kind, prev_mode: self.tokens.mode() }); self.tokens.set_mode(match kind { Group::Bracket | Group::Strong | Group::Emph => TokenMode::Markup, - Group::Paren | Group::Brace | Group::Expr | Group::Imports => TokenMode::Code, + Group::Brace | Group::Paren | Group::Expr | Group::Imports => TokenMode::Code, }); match kind { - Group::Paren => self.eat_assert(&NodeKind::LeftParen), - Group::Bracket => self.eat_assert(&NodeKind::LeftBracket), Group::Brace => self.eat_assert(&NodeKind::LeftBrace), + Group::Bracket => self.eat_assert(&NodeKind::LeftBracket), + Group::Paren => self.eat_assert(&NodeKind::LeftParen), Group::Strong => self.eat_assert(&NodeKind::Star), Group::Emph => self.eat_assert(&NodeKind::Underscore), Group::Expr => self.repeek(), @@ -321,9 +321,9 @@ impl<'s> Parser<'s> { /// group. fn repeek(&mut self) { self.eof = match &self.current { - Some(NodeKind::RightParen) => self.inside(Group::Paren), - Some(NodeKind::RightBracket) => self.inside(Group::Bracket), Some(NodeKind::RightBrace) => self.inside(Group::Brace), + Some(NodeKind::RightBracket) => self.inside(Group::Bracket), + Some(NodeKind::RightParen) => self.inside(Group::Paren), Some(NodeKind::Star) => self.inside(Group::Strong), Some(NodeKind::Underscore) => self.inside(Group::Emph), Some(NodeKind::Semicolon) => self.inside(Group::Expr), @@ -482,10 +482,10 @@ struct GroupEntry { /// A group, confined by optional start and end delimiters. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum Group { - /// A bracketed group: `[...]`. - Bracket, /// A curly-braced group: `{...}`. Brace, + /// A bracketed group: `[...]`. + Bracket, /// A parenthesized group: `(...)`. Paren, /// A group surrounded with stars: `*...*`. diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs index 91bbf9e84..752714fd3 100644 --- a/src/parse/tokens.rs +++ b/src/parse/tokens.rs @@ -26,7 +26,7 @@ pub struct Tokens<'s> { pub enum TokenMode { /// Text and markup. Markup, - /// Blocks and expressions. + /// Keywords, literals and operators. Code, } @@ -104,11 +104,11 @@ impl<'s> Iterator for Tokens<'s> { let start = self.s.index(); let c = self.s.eat()?; Some(match c { - // Blocks and templates. - '[' => NodeKind::LeftBracket, - ']' => NodeKind::RightBracket, + // Blocks. '{' => NodeKind::LeftBrace, '}' => NodeKind::RightBrace, + '[' => NodeKind::LeftBracket, + ']' => NodeKind::RightBracket, // Whitespace. ' ' if self.s.check_or(true, |c| !c.is_whitespace()) => NodeKind::Space(0), @@ -741,18 +741,18 @@ mod tests { #[test] fn test_tokenize_brackets() { // Test in markup. - t!(Markup: "[" => LeftBracket); - t!(Markup: "]" => RightBracket); t!(Markup: "{" => LeftBrace); t!(Markup: "}" => RightBrace); + t!(Markup: "[" => LeftBracket); + t!(Markup: "]" => RightBracket); t!(Markup[" /"]: "(" => Text("(")); t!(Markup[" /"]: ")" => Text(")")); // Test in code. - t!(Code: "[" => LeftBracket); - t!(Code: "]" => RightBracket); t!(Code: "{" => LeftBrace); t!(Code: "}" => RightBrace); + t!(Code: "[" => LeftBracket); + t!(Code: "]" => RightBracket); t!(Code: "(" => LeftParen); t!(Code: ")" => RightParen); } diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs index 10e5ec70d..425af0c1b 100644 --- a/src/syntax/ast.rs +++ b/src/syntax/ast.rs @@ -67,9 +67,9 @@ impl Markup { Some(MarkupNode::Text(s.clone())) } NodeKind::Escape(c) => Some(MarkupNode::Text((*c).into())), + NodeKind::NonBreakingSpace => Some(MarkupNode::Text('\u{00A0}'.into())), NodeKind::EnDash => Some(MarkupNode::Text('\u{2013}'.into())), NodeKind::EmDash => Some(MarkupNode::Text('\u{2014}'.into())), - NodeKind::NonBreakingSpace => Some(MarkupNode::Text('\u{00A0}'.into())), NodeKind::Strong => node.cast().map(MarkupNode::Strong), NodeKind::Emph => node.cast().map(MarkupNode::Emph), NodeKind::Raw(raw) => Some(MarkupNode::Raw(raw.as_ref().clone())), @@ -219,16 +219,16 @@ pub enum Expr { Lit(Lit), /// An identifier: `left`. Ident(Ident), + /// A code block: `{ let x = 1; x + 2 }`. + Code(CodeBlock), + /// A template block: `[*Hi* there!]`. + Template(TemplateBlock), + /// A grouped expression: `(1 + 2)`. + Group(GroupExpr), /// 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`. @@ -269,15 +269,15 @@ impl TypedNode for Expr { fn from_red(node: RedRef) -> Option { match node.kind() { NodeKind::Ident(_) => node.cast().map(Self::Ident), - NodeKind::Array => node.cast().map(Self::Array), - NodeKind::Dict => node.cast().map(Self::Dict), - NodeKind::Template => node.cast().map(Self::Template), - NodeKind::Group => node.cast().map(Self::Group), - NodeKind::Block => node.cast().map(Self::Block), - NodeKind::Unary => node.cast().map(Self::Unary), - NodeKind::Binary => node.cast().map(Self::Binary), - NodeKind::Call => node.cast().map(Self::Call), - NodeKind::Closure => node.cast().map(Self::Closure), + NodeKind::CodeBlock => node.cast().map(Self::Code), + NodeKind::TemplateBlock => node.cast().map(Self::Template), + NodeKind::GroupExpr => node.cast().map(Self::Group), + NodeKind::ArrayExpr => node.cast().map(Self::Array), + NodeKind::DictExpr => node.cast().map(Self::Dict), + NodeKind::UnaryExpr => node.cast().map(Self::Unary), + NodeKind::BinaryExpr => node.cast().map(Self::Binary), + NodeKind::CallExpr => node.cast().map(Self::Call), + NodeKind::ClosureExpr => node.cast().map(Self::Closure), NodeKind::WithExpr => node.cast().map(Self::With), NodeKind::LetExpr => node.cast().map(Self::Let), NodeKind::SetExpr => node.cast().map(Self::Set), @@ -298,12 +298,12 @@ impl TypedNode for Expr { fn as_red(&self) -> RedRef<'_> { match self { Self::Lit(v) => v.as_red(), + Self::Code(v) => v.as_red(), + Self::Template(v) => v.as_red(), Self::Ident(v) => v.as_red(), Self::Array(v) => v.as_red(), Self::Dict(v) => v.as_red(), - Self::Template(v) => v.as_red(), Self::Group(v) => v.as_red(), - Self::Block(v) => v.as_red(), Self::Unary(v) => v.as_red(), Self::Binary(v) => v.as_red(), Self::Call(v) => v.as_red(), @@ -406,9 +406,45 @@ pub enum LitKind { Str(EcoString), } +node! { + /// A code block: `{ let x = 1; x + 2 }`. + CodeBlock: CodeBlock +} + +impl CodeBlock { + /// The list of expressions contained in the block. + pub fn exprs(&self) -> impl Iterator + '_ { + self.0.children().filter_map(RedRef::cast) + } +} + +node! { + /// A template block: `[*Hi* there!]`. + TemplateBlock: TemplateBlock +} + +impl TemplateBlock { + /// The contents of the template. + pub fn body(&self) -> Markup { + self.0.cast_first_child().expect("template is missing body") + } +} + +node! { + /// A grouped expression: `(1 + 2)`. + GroupExpr: GroupExpr +} + +impl GroupExpr { + /// The wrapped expression. + pub fn expr(&self) -> Expr { + self.0.cast_first_child().expect("group is missing expression") + } +} + node! { /// An array expression: `(1, "hi", 12cm)`. - ArrayExpr: Array + ArrayExpr: ArrayExpr } impl ArrayExpr { @@ -420,7 +456,7 @@ impl ArrayExpr { node! { /// A dictionary expression: `(thickness: 3pt, pattern: dashed)`. - DictExpr: Dict + DictExpr: DictExpr } impl DictExpr { @@ -447,45 +483,9 @@ impl Named { } } -node! { - /// A template expression: `[*Hi* there!]`. - TemplateExpr: Template -} - -impl TemplateExpr { - /// The contents of the template. - pub fn body(&self) -> Markup { - self.0.cast_first_child().expect("template is missing body") - } -} - -node! { - /// A grouped expression: `(1 + 2)`. - GroupExpr: Group -} - -impl GroupExpr { - /// The wrapped expression. - pub fn expr(&self) -> Expr { - self.0.cast_first_child().expect("group is missing expression") - } -} - -node! { - /// A block expression: `{ let x = 1; x + 2 }`. - BlockExpr: Block -} - -impl BlockExpr { - /// The list of expressions contained in the block. - pub fn exprs(&self) -> impl Iterator + '_ { - self.0.children().filter_map(RedRef::cast) - } -} - node! { /// A unary operation: `-x`. - UnaryExpr: Unary + UnaryExpr: UnaryExpr } impl UnaryExpr { @@ -545,7 +545,7 @@ impl UnOp { node! { /// A binary operation: `a + b`. - BinaryExpr: Binary + BinaryExpr: BinaryExpr } impl BinaryExpr { @@ -717,7 +717,7 @@ pub enum Associativity { node! { /// An invocation of a function: `foo(...)`. - CallExpr: Call + CallExpr: CallExpr } impl CallExpr { @@ -786,7 +786,7 @@ impl CallArg { node! { /// A closure expression: `(x, y) => z`. - ClosureExpr: Closure + ClosureExpr: ClosureExpr } impl ClosureExpr { diff --git a/src/syntax/highlight.rs b/src/syntax/highlight.rs index 82f1ea0e8..20ea40396 100644 --- a/src/syntax/highlight.rs +++ b/src/syntax/highlight.rs @@ -104,10 +104,10 @@ impl Category { /// Determine the highlighting category of a node given its parent. pub fn determine(child: RedRef, parent: RedRef) -> Option { match child.kind() { - NodeKind::LeftBracket => Some(Category::Bracket), - NodeKind::RightBracket => Some(Category::Bracket), NodeKind::LeftBrace => Some(Category::Bracket), NodeKind::RightBrace => Some(Category::Bracket), + NodeKind::LeftBracket => Some(Category::Bracket), + NodeKind::RightBracket => Some(Category::Bracket), NodeKind::LeftParen => Some(Category::Bracket), NodeKind::RightParen => Some(Category::Bracket), NodeKind::Comma => Some(Category::Punctuation), @@ -176,13 +176,13 @@ impl Category { NodeKind::Auto => Some(Category::Auto), NodeKind::Ident(_) => match parent.kind() { NodeKind::Named => None, - NodeKind::Closure if child.span().start == parent.span().start => { + NodeKind::ClosureExpr if child.span().start == parent.span().start => { Some(Category::Function) } NodeKind::WithExpr => Some(Category::Function), NodeKind::SetExpr => Some(Category::Function), NodeKind::ShowExpr => Some(Category::Function), - NodeKind::Call => Some(Category::Function), + NodeKind::CallExpr => Some(Category::Function), _ => Some(Category::Variable), }, NodeKind::Bool(_) => Some(Category::Bool), @@ -202,18 +202,18 @@ impl Category { NodeKind::TextInLine(_) => None, NodeKind::List => None, NodeKind::Enum => None, - NodeKind::Array => None, - NodeKind::Dict => None, + NodeKind::CodeBlock => None, + NodeKind::TemplateBlock => None, + NodeKind::GroupExpr => None, + NodeKind::ArrayExpr => None, + NodeKind::DictExpr => None, NodeKind::Named => None, - NodeKind::Template => None, - NodeKind::Group => None, - NodeKind::Block => None, - NodeKind::Unary => None, - NodeKind::Binary => None, - NodeKind::Call => None, + NodeKind::UnaryExpr => None, + NodeKind::BinaryExpr => None, + NodeKind::CallExpr => None, NodeKind::CallArgs => None, NodeKind::Spread => None, - NodeKind::Closure => None, + NodeKind::ClosureExpr => None, NodeKind::ClosureParams => None, NodeKind::WithExpr => None, NodeKind::LetExpr => None, diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index 85f2013c4..a3393eda9 100644 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -481,14 +481,14 @@ impl ExactSizeIterator for Children<'_> {} /// the parser. #[derive(Debug, Clone, PartialEq)] pub enum NodeKind { - /// A left square bracket: `[`. - LeftBracket, - /// A right square bracket: `]`. - RightBracket, /// A left curly brace: `{`. LeftBrace, /// A right curly brace: `}`. RightBrace, + /// A left square bracket: `[`. + LeftBracket, + /// A right square bracket: `]`. + RightBracket, /// A left round parenthesis: `(`. LeftParen, /// A right round parenthesis: `)`. @@ -642,30 +642,30 @@ pub enum NodeKind { Fraction(f64), /// A quoted string: `"..."`. Str(EcoString), + /// A code block: `{ let x = 1; x + 2 }`. + CodeBlock, + /// A template block: `[*Hi* there!]`. + TemplateBlock, + /// A grouped expression: `(1 + 2)`. + GroupExpr, /// An array expression: `(1, "hi", 12cm)`. - Array, + ArrayExpr, /// A dictionary expression: `(thickness: 3pt, pattern: dashed)`. - Dict, + DictExpr, /// A named pair: `thickness: 3pt`. Named, - /// A template expression: `[*Hi* there!]`. - Template, - /// A grouped expression: `(1 + 2)`. - Group, - /// A block expression: `{ let x = 1; x + 2 }`. - Block, /// A unary operation: `-x`. - Unary, + UnaryExpr, /// A binary operation: `a + b`. - Binary, + BinaryExpr, /// An invocation of a function: `f(x, y)`. - Call, + CallExpr, /// A function call's argument list: `(x, y)`. CallArgs, /// Spreaded arguments or a parameter sink: `..x`. Spread, /// A closure expression: `(x, y) => z`. - Closure, + ClosureExpr, /// A closure's parameters: `(x, y)`. ClosureParams, /// A with expression: `f with (x, y: 1)`. @@ -724,16 +724,16 @@ pub enum ErrorPos { } impl NodeKind { - /// Whether this is some kind of bracket. - pub fn is_bracket(&self) -> bool { - matches!(self, Self::LeftBracket | Self::RightBracket) - } - /// Whether this is some kind of brace. pub fn is_brace(&self) -> bool { matches!(self, Self::LeftBrace | Self::RightBrace) } + /// Whether this is some kind of bracket. + pub fn is_bracket(&self) -> bool { + matches!(self, Self::LeftBracket | Self::RightBracket) + } + /// Whether this is some kind of parenthesis. pub fn is_paren(&self) -> bool { matches!(self, Self::LeftParen | Self::RightParen) @@ -782,10 +782,10 @@ impl NodeKind { | Self::List | Self::Raw(_) | Self::Math(_) => Some(TokenMode::Markup), - Self::Template + Self::TemplateBlock | Self::Space(_) - | Self::Block | Self::Ident(_) + | Self::CodeBlock | Self::LetExpr | Self::SetExpr | Self::ShowExpr @@ -794,7 +794,7 @@ impl NodeKind { | Self::WhileExpr | Self::ForExpr | Self::ImportExpr - | Self::Call + | Self::CallExpr | Self::IncludeExpr | Self::LineComment | Self::BlockComment @@ -808,10 +808,10 @@ impl NodeKind { /// A human-readable name for the kind. pub fn as_str(&self) -> &'static str { match self { - Self::LeftBracket => "opening bracket", - Self::RightBracket => "closing bracket", Self::LeftBrace => "opening brace", Self::RightBrace => "closing brace", + Self::LeftBracket => "opening bracket", + Self::RightBracket => "closing bracket", Self::LeftParen => "opening paren", Self::RightParen => "closing paren", Self::Star => "star", @@ -883,18 +883,18 @@ impl NodeKind { Self::Percentage(_) => "percentage", Self::Fraction(_) => "`fr` value", Self::Str(_) => "string", - Self::Array => "array", - Self::Dict => "dictionary", + Self::CodeBlock => "code block", + Self::TemplateBlock => "template block", + Self::GroupExpr => "group", + Self::ArrayExpr => "array", + Self::DictExpr => "dictionary", Self::Named => "named argument", - Self::Template => "template", - Self::Group => "group", - Self::Block => "block", - Self::Unary => "unary expression", - Self::Binary => "binary expression", - Self::Call => "call", + Self::UnaryExpr => "unary expression", + Self::BinaryExpr => "binary expression", + Self::CallExpr => "call", Self::CallArgs => "call arguments", Self::Spread => "parameter sink", - Self::Closure => "closure", + Self::ClosureExpr => "closure", Self::ClosureParams => "closure parameters", Self::WithExpr => "`with` expression", Self::LetExpr => "`let` expression", @@ -932,10 +932,10 @@ impl Hash for NodeKind { fn hash(&self, state: &mut H) { std::mem::discriminant(self).hash(state); match self { - Self::LeftBracket => {} - Self::RightBracket => {} Self::LeftBrace => {} Self::RightBrace => {} + Self::LeftBracket => {} + Self::RightBracket => {} Self::LeftParen => {} Self::RightParen => {} Self::Star => {} @@ -1007,18 +1007,18 @@ impl Hash for NodeKind { Self::Percentage(v) => v.to_bits().hash(state), Self::Fraction(v) => v.to_bits().hash(state), Self::Str(v) => v.hash(state), - Self::Array => {} - Self::Dict => {} + Self::CodeBlock => {} + Self::TemplateBlock => {} + Self::GroupExpr => {} + Self::ArrayExpr => {} + Self::DictExpr => {} Self::Named => {} - Self::Template => {} - Self::Group => {} - Self::Block => {} - Self::Unary => {} - Self::Binary => {} - Self::Call => {} + Self::UnaryExpr => {} + Self::BinaryExpr => {} + Self::CallExpr => {} Self::CallArgs => {} Self::Spread => {} - Self::Closure => {} + Self::ClosureExpr => {} Self::ClosureParams => {} Self::WithExpr => {} Self::LetExpr => {}