Consistent block naming

This commit is contained in:
Laurenz 2022-03-11 12:22:27 +01:00
parent e6b532391d
commit 5ce2a006b6
12 changed files with 269 additions and 279 deletions

View File

@ -49,6 +49,15 @@ impl<'a> CapturesVisitor<'a> {
// through the expressions that contain them). // through the expressions that contain them).
Some(Expr::Ident(ident)) => self.capture(ident), 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 // A closure contains parameter bindings, which are bound before the
// body is evaluated. Care must be taken so that the default values // body is evaluated. Care must be taken so that the default values
// of named parameters cannot access previous parameter bindings. // 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. // Everything else is traversed from left to right.
_ => { _ => {
for child in node.children() { for child in node.children() {

View File

@ -202,11 +202,11 @@ impl Eval for Expr {
match self { match self {
Self::Lit(v) => v.eval(ctx, scp), Self::Lit(v) => v.eval(ctx, scp),
Self::Ident(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::Array(v) => v.eval(ctx, scp).map(Value::Array),
Self::Dict(v) => v.eval(ctx, scp).map(Value::Dict), 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::Group(v) => v.eval(ctx, scp),
Self::Block(v) => v.eval(ctx, scp),
Self::Call(v) => v.eval(ctx, scp), Self::Call(v) => v.eval(ctx, scp),
Self::Closure(v) => v.eval(ctx, scp), Self::Closure(v) => v.eval(ctx, scp),
Self::With(v) => v.eval(ctx, scp), Self::With(v) => v.eval(ctx, scp),
@ -260,25 +260,23 @@ impl Eval for Ident {
} }
} }
impl Eval for ArrayExpr { impl Eval for CodeBlock {
type Output = Array; type Output = Value;
fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> {
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 { impl Eval for TemplateBlock {
type Output = Dict;
fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> {
self.items()
.map(|x| Ok((x.name().take(), x.expr().eval(ctx, scp)?)))
.collect()
}
}
impl Eval for TemplateExpr {
type Output = Template; type Output = Template;
fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> {
@ -297,19 +295,21 @@ impl Eval for GroupExpr {
} }
} }
impl Eval for BlockExpr { impl Eval for ArrayExpr {
type Output = Value; type Output = Array;
fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> {
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())?;
} }
scp.exit(); impl Eval for DictExpr {
Ok(output) type Output = Dict;
fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> {
self.items()
.map(|x| Ok((x.name().take(), x.expr().eval(ctx, scp)?)))
.collect()
} }
} }

View File

@ -5,7 +5,7 @@ use std::hash::{Hash, Hasher};
use std::sync::Arc; use std::sync::Arc;
use super::{ops, Args, Array, Class, Dict, Func, Layout, Template}; 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::geom::{Angle, Color, Fractional, Length, Linear, Relative, RgbaColor};
use crate::syntax::Spanned; use crate::syntax::Spanned;
use crate::util::EcoString; use crate::util::EcoString;
@ -533,16 +533,6 @@ impl<T: Cast> Cast for Smart<T> {
} }
} }
/// 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)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@ -1,3 +1,5 @@
//! Mathematical formulas.
use crate::library::prelude::*; use crate::library::prelude::*;
/// A mathematical formula. /// A mathematical formula.

View File

@ -1,4 +1,4 @@
//! Text shaping and paragraph layout. //! Text handling and paragraph layout.
mod deco; mod deco;
mod link; mod link;

View File

@ -136,8 +136,8 @@ impl Reparser<'_> {
let superseded_span = pos.offset .. pos.offset + prev_len; let superseded_span = pos.offset .. pos.offset + prev_len;
let func: Option<ReparseMode> = match child.kind() { let func: Option<ReparseMode> = match child.kind() {
NodeKind::Template => Some(ReparseMode::Template), NodeKind::CodeBlock => Some(ReparseMode::Code),
NodeKind::Block => Some(ReparseMode::Block), NodeKind::TemplateBlock => Some(ReparseMode::Template),
_ => None, _ => None,
}; };
@ -211,7 +211,7 @@ impl Reparser<'_> {
} }
let (newborns, terminated, amount) = match mode { let (newborns, terminated, amount) = match mode {
ReparseMode::Block => reparse_block( ReparseMode::Code => reparse_block(
&prefix, &prefix,
&self.src[newborn_span.start ..], &self.src[newborn_span.start ..],
newborn_span.len(), newborn_span.len(),
@ -292,9 +292,9 @@ impl SearchState {
/// Which reparse function to choose for a span of elements. /// Which reparse function to choose for a span of elements.
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
enum ReparseMode { enum ReparseMode {
/// Reparse a code block with its braces. /// Reparse a code block, including its braces.
Block, Code,
/// Reparse a template, including its square brackets. /// Reparse a template block, including its square brackets.
Template, Template,
/// Reparse elements of the markup. The variant carries whether the node is /// Reparse elements of the markup. The variant carries whether the node is
/// `at_start` and the minimum indent of the containing markup node. /// `at_start` and the minimum indent of the containing markup node.

View File

@ -28,8 +28,57 @@ pub fn parse(src: &str) -> Arc<GreenNode> {
} }
} }
/// Parse some markup without the topmost node. Returns `Some` if all of the /// Reparse a code block.
/// input was consumed. ///
/// Returns `Some` if all of the input was consumed.
pub fn reparse_block(
prefix: &str,
src: &str,
end_pos: usize,
) -> Option<(Vec<Green>, 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<Green>, 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( pub fn reparse_markup_elements(
prefix: &str, prefix: &str,
src: &str, src: &str,
@ -100,50 +149,6 @@ pub fn reparse_markup_elements(
Some((res, terminated, replaced)) 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<Green>, 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<Green>, 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. /// Parse markup.
/// ///
/// If `at_start` is true, things like headings that may only appear at the /// 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. // Text and markup.
NodeKind::Text(_) NodeKind::Text(_)
| NodeKind::NonBreakingSpace
| NodeKind::EnDash | NodeKind::EnDash
| NodeKind::EmDash | NodeKind::EmDash
| NodeKind::NonBreakingSpace
| NodeKind::Linebreak | NodeKind::Linebreak
| NodeKind::Raw(_) | NodeKind::Raw(_)
| NodeKind::Math(_) | NodeKind::Math(_)
@ -350,7 +355,7 @@ fn expr_prec(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult {
p.eat(); p.eat();
let prec = op.precedence(); let prec = op.precedence();
expr_prec(p, atomic, prec)?; expr_prec(p, atomic, prec)?;
marker.end(p, NodeKind::Unary); marker.end(p, NodeKind::UnaryExpr);
} }
_ => primary(p, atomic)?, _ => primary(p, atomic)?,
}; };
@ -388,7 +393,7 @@ fn expr_prec(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult {
Associativity::Right => {} 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(()) Ok(())
@ -410,7 +415,7 @@ fn primary(p: &mut Parser, atomic: bool) -> ParseResult {
if !atomic && p.at(&NodeKind::Arrow) { if !atomic && p.at(&NodeKind::Arrow) {
marker.end(p, NodeKind::ClosureParams); marker.end(p, NodeKind::ClosureParams);
p.eat_assert(&NodeKind::Arrow); p.eat_assert(&NodeKind::Arrow);
marker.perform(p, NodeKind::Closure, expr) marker.perform(p, NodeKind::ClosureExpr, expr)
} else { } else {
Ok(()) Ok(())
} }
@ -418,14 +423,8 @@ fn primary(p: &mut Parser, atomic: bool) -> ParseResult {
// Structures. // Structures.
Some(NodeKind::LeftParen) => parenthesized(p, atomic), Some(NodeKind::LeftParen) => parenthesized(p, atomic),
Some(NodeKind::LeftBracket) => { Some(NodeKind::LeftBrace) => Ok(block(p)),
template(p); Some(NodeKind::LeftBracket) => Ok(template(p)),
Ok(())
}
Some(NodeKind::LeftBrace) => {
block(p);
Ok(())
}
// Keywords. // Keywords.
Some(NodeKind::Let) => let_expr(p), 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: /// Parse something that starts with a parenthesis, which can be either of:
/// - Array literal /// - Array literal
/// - Dictionary literal /// - Dictionary literal
@ -501,12 +514,12 @@ fn parenthesized(p: &mut Parser, atomic: bool) -> ParseResult {
if !atomic && p.at(&NodeKind::Arrow) { if !atomic && p.at(&NodeKind::Arrow) {
params(p, marker); params(p, marker);
p.eat_assert(&NodeKind::Arrow); p.eat_assert(&NodeKind::Arrow);
return marker.perform(p, NodeKind::Closure, expr); return marker.perform(p, NodeKind::ClosureExpr, expr);
} }
// Transform into the identified collection. // Transform into the identified collection.
match kind { match kind {
CollectionKind::Group => marker.end(p, NodeKind::Group), CollectionKind::Group => marker.end(p, NodeKind::GroupExpr),
CollectionKind::Positional => array(p, marker), CollectionKind::Positional => array(p, marker),
CollectionKind::Named => dict(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"), NodeKind::Spread => Err("spreading is not allowed here"),
_ => Ok(()), _ => Ok(()),
}); });
marker.end(p, NodeKind::Array); marker.end(p, NodeKind::ArrayExpr);
} }
/// Convert a collection into a dictionary, producing errors for anything other /// 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"), NodeKind::Spread => Err("spreading is not allowed here"),
_ => Err("expected named pair, found expression"), _ => 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 /// 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); 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: `{...}`. /// Parse a code block: `{...}`.
fn block(p: &mut Parser) { fn block(p: &mut Parser) {
p.perform(NodeKind::Block, |p| { p.perform(NodeKind::CodeBlock, |p| {
p.start_group(Group::Brace); p.start_group(Group::Brace);
while !p.eof() { while !p.eof() {
p.start_group(Group::Expr); 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. /// Parse a function call.
fn call(p: &mut Parser, callee: Marker) -> ParseResult { 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. /// 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. // Rewrite into a closure expression if it's a function definition.
if has_params { 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"); p.expected_found("parameter list");
return Err(ParseError); return Err(ParseError);
} }
p.perform(NodeKind::Closure, |p| { p.perform(NodeKind::ClosureExpr, |p| {
let marker = p.marker(); let marker = p.marker();
p.start_group(Group::Paren); p.start_group(Group::Paren);
collection(p); 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. /// Parse a control flow body.
fn body(p: &mut Parser) -> ParseResult { fn body(p: &mut Parser) -> ParseResult {
match p.peek() { match p.peek() {
Some(NodeKind::LeftBracket) => template(p), Some(NodeKind::LeftBracket) => Ok(template(p)),
Some(NodeKind::LeftBrace) => block(p), Some(NodeKind::LeftBrace) => Ok(block(p)),
_ => { _ => {
p.expected("body"); p.expected("body");
return Err(ParseError); Err(ParseError)
} }
} }
Ok(())
} }
#[cfg(test)] #[cfg(test)]

View File

@ -229,13 +229,13 @@ impl<'s> Parser<'s> {
self.groups.push(GroupEntry { kind, prev_mode: self.tokens.mode() }); self.groups.push(GroupEntry { kind, prev_mode: self.tokens.mode() });
self.tokens.set_mode(match kind { self.tokens.set_mode(match kind {
Group::Bracket | Group::Strong | Group::Emph => TokenMode::Markup, 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 { match kind {
Group::Paren => self.eat_assert(&NodeKind::LeftParen),
Group::Bracket => self.eat_assert(&NodeKind::LeftBracket),
Group::Brace => self.eat_assert(&NodeKind::LeftBrace), 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::Strong => self.eat_assert(&NodeKind::Star),
Group::Emph => self.eat_assert(&NodeKind::Underscore), Group::Emph => self.eat_assert(&NodeKind::Underscore),
Group::Expr => self.repeek(), Group::Expr => self.repeek(),
@ -321,9 +321,9 @@ impl<'s> Parser<'s> {
/// group. /// group.
fn repeek(&mut self) { fn repeek(&mut self) {
self.eof = match &self.current { 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::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::Star) => self.inside(Group::Strong),
Some(NodeKind::Underscore) => self.inside(Group::Emph), Some(NodeKind::Underscore) => self.inside(Group::Emph),
Some(NodeKind::Semicolon) => self.inside(Group::Expr), Some(NodeKind::Semicolon) => self.inside(Group::Expr),
@ -482,10 +482,10 @@ struct GroupEntry {
/// A group, confined by optional start and end delimiters. /// A group, confined by optional start and end delimiters.
#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Group { pub enum Group {
/// A bracketed group: `[...]`.
Bracket,
/// A curly-braced group: `{...}`. /// A curly-braced group: `{...}`.
Brace, Brace,
/// A bracketed group: `[...]`.
Bracket,
/// A parenthesized group: `(...)`. /// A parenthesized group: `(...)`.
Paren, Paren,
/// A group surrounded with stars: `*...*`. /// A group surrounded with stars: `*...*`.

View File

@ -26,7 +26,7 @@ pub struct Tokens<'s> {
pub enum TokenMode { pub enum TokenMode {
/// Text and markup. /// Text and markup.
Markup, Markup,
/// Blocks and expressions. /// Keywords, literals and operators.
Code, Code,
} }
@ -104,11 +104,11 @@ impl<'s> Iterator for Tokens<'s> {
let start = self.s.index(); let start = self.s.index();
let c = self.s.eat()?; let c = self.s.eat()?;
Some(match c { Some(match c {
// Blocks and templates. // Blocks.
'[' => NodeKind::LeftBracket,
']' => NodeKind::RightBracket,
'{' => NodeKind::LeftBrace, '{' => NodeKind::LeftBrace,
'}' => NodeKind::RightBrace, '}' => NodeKind::RightBrace,
'[' => NodeKind::LeftBracket,
']' => NodeKind::RightBracket,
// Whitespace. // Whitespace.
' ' if self.s.check_or(true, |c| !c.is_whitespace()) => NodeKind::Space(0), ' ' if self.s.check_or(true, |c| !c.is_whitespace()) => NodeKind::Space(0),
@ -741,18 +741,18 @@ mod tests {
#[test] #[test]
fn test_tokenize_brackets() { fn test_tokenize_brackets() {
// Test in markup. // Test in markup.
t!(Markup: "[" => LeftBracket);
t!(Markup: "]" => RightBracket);
t!(Markup: "{" => LeftBrace); t!(Markup: "{" => LeftBrace);
t!(Markup: "}" => RightBrace); t!(Markup: "}" => RightBrace);
t!(Markup: "[" => LeftBracket);
t!(Markup: "]" => RightBracket);
t!(Markup[" /"]: "(" => Text("(")); t!(Markup[" /"]: "(" => Text("("));
t!(Markup[" /"]: ")" => Text(")")); t!(Markup[" /"]: ")" => Text(")"));
// Test in code. // Test in code.
t!(Code: "[" => LeftBracket);
t!(Code: "]" => RightBracket);
t!(Code: "{" => LeftBrace); t!(Code: "{" => LeftBrace);
t!(Code: "}" => RightBrace); t!(Code: "}" => RightBrace);
t!(Code: "[" => LeftBracket);
t!(Code: "]" => RightBracket);
t!(Code: "(" => LeftParen); t!(Code: "(" => LeftParen);
t!(Code: ")" => RightParen); t!(Code: ")" => RightParen);
} }

View File

@ -67,9 +67,9 @@ impl Markup {
Some(MarkupNode::Text(s.clone())) Some(MarkupNode::Text(s.clone()))
} }
NodeKind::Escape(c) => Some(MarkupNode::Text((*c).into())), 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::EnDash => Some(MarkupNode::Text('\u{2013}'.into())),
NodeKind::EmDash => Some(MarkupNode::Text('\u{2014}'.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::Strong => node.cast().map(MarkupNode::Strong),
NodeKind::Emph => node.cast().map(MarkupNode::Emph), NodeKind::Emph => node.cast().map(MarkupNode::Emph),
NodeKind::Raw(raw) => Some(MarkupNode::Raw(raw.as_ref().clone())), NodeKind::Raw(raw) => Some(MarkupNode::Raw(raw.as_ref().clone())),
@ -219,16 +219,16 @@ pub enum Expr {
Lit(Lit), Lit(Lit),
/// An identifier: `left`. /// An identifier: `left`.
Ident(Ident), 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)`. /// An array expression: `(1, "hi", 12cm)`.
Array(ArrayExpr), Array(ArrayExpr),
/// A dictionary expression: `(thickness: 3pt, pattern: dashed)`. /// A dictionary expression: `(thickness: 3pt, pattern: dashed)`.
Dict(DictExpr), 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`. /// A unary operation: `-x`.
Unary(UnaryExpr), Unary(UnaryExpr),
/// A binary operation: `a + b`. /// A binary operation: `a + b`.
@ -269,15 +269,15 @@ impl TypedNode for Expr {
fn from_red(node: RedRef) -> Option<Self> { fn from_red(node: RedRef) -> Option<Self> {
match node.kind() { match node.kind() {
NodeKind::Ident(_) => node.cast().map(Self::Ident), NodeKind::Ident(_) => node.cast().map(Self::Ident),
NodeKind::Array => node.cast().map(Self::Array), NodeKind::CodeBlock => node.cast().map(Self::Code),
NodeKind::Dict => node.cast().map(Self::Dict), NodeKind::TemplateBlock => node.cast().map(Self::Template),
NodeKind::Template => node.cast().map(Self::Template), NodeKind::GroupExpr => node.cast().map(Self::Group),
NodeKind::Group => node.cast().map(Self::Group), NodeKind::ArrayExpr => node.cast().map(Self::Array),
NodeKind::Block => node.cast().map(Self::Block), NodeKind::DictExpr => node.cast().map(Self::Dict),
NodeKind::Unary => node.cast().map(Self::Unary), NodeKind::UnaryExpr => node.cast().map(Self::Unary),
NodeKind::Binary => node.cast().map(Self::Binary), NodeKind::BinaryExpr => node.cast().map(Self::Binary),
NodeKind::Call => node.cast().map(Self::Call), NodeKind::CallExpr => node.cast().map(Self::Call),
NodeKind::Closure => node.cast().map(Self::Closure), NodeKind::ClosureExpr => node.cast().map(Self::Closure),
NodeKind::WithExpr => node.cast().map(Self::With), NodeKind::WithExpr => node.cast().map(Self::With),
NodeKind::LetExpr => node.cast().map(Self::Let), NodeKind::LetExpr => node.cast().map(Self::Let),
NodeKind::SetExpr => node.cast().map(Self::Set), NodeKind::SetExpr => node.cast().map(Self::Set),
@ -298,12 +298,12 @@ impl TypedNode for Expr {
fn as_red(&self) -> RedRef<'_> { fn as_red(&self) -> RedRef<'_> {
match self { match self {
Self::Lit(v) => v.as_red(), 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::Ident(v) => v.as_red(),
Self::Array(v) => v.as_red(), Self::Array(v) => v.as_red(),
Self::Dict(v) => v.as_red(), Self::Dict(v) => v.as_red(),
Self::Template(v) => v.as_red(),
Self::Group(v) => v.as_red(), Self::Group(v) => v.as_red(),
Self::Block(v) => v.as_red(),
Self::Unary(v) => v.as_red(), Self::Unary(v) => v.as_red(),
Self::Binary(v) => v.as_red(), Self::Binary(v) => v.as_red(),
Self::Call(v) => v.as_red(), Self::Call(v) => v.as_red(),
@ -406,9 +406,45 @@ pub enum LitKind {
Str(EcoString), 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<Item = Expr> + '_ {
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! { node! {
/// An array expression: `(1, "hi", 12cm)`. /// An array expression: `(1, "hi", 12cm)`.
ArrayExpr: Array ArrayExpr: ArrayExpr
} }
impl ArrayExpr { impl ArrayExpr {
@ -420,7 +456,7 @@ impl ArrayExpr {
node! { node! {
/// A dictionary expression: `(thickness: 3pt, pattern: dashed)`. /// A dictionary expression: `(thickness: 3pt, pattern: dashed)`.
DictExpr: Dict DictExpr: DictExpr
} }
impl 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<Item = Expr> + '_ {
self.0.children().filter_map(RedRef::cast)
}
}
node! { node! {
/// A unary operation: `-x`. /// A unary operation: `-x`.
UnaryExpr: Unary UnaryExpr: UnaryExpr
} }
impl UnaryExpr { impl UnaryExpr {
@ -545,7 +545,7 @@ impl UnOp {
node! { node! {
/// A binary operation: `a + b`. /// A binary operation: `a + b`.
BinaryExpr: Binary BinaryExpr: BinaryExpr
} }
impl BinaryExpr { impl BinaryExpr {
@ -717,7 +717,7 @@ pub enum Associativity {
node! { node! {
/// An invocation of a function: `foo(...)`. /// An invocation of a function: `foo(...)`.
CallExpr: Call CallExpr: CallExpr
} }
impl CallExpr { impl CallExpr {
@ -786,7 +786,7 @@ impl CallArg {
node! { node! {
/// A closure expression: `(x, y) => z`. /// A closure expression: `(x, y) => z`.
ClosureExpr: Closure ClosureExpr: ClosureExpr
} }
impl ClosureExpr { impl ClosureExpr {

View File

@ -104,10 +104,10 @@ impl Category {
/// Determine the highlighting category of a node given its parent. /// Determine the highlighting category of a node given its parent.
pub fn determine(child: RedRef, parent: RedRef) -> Option<Category> { pub fn determine(child: RedRef, parent: RedRef) -> Option<Category> {
match child.kind() { match child.kind() {
NodeKind::LeftBracket => Some(Category::Bracket),
NodeKind::RightBracket => Some(Category::Bracket),
NodeKind::LeftBrace => Some(Category::Bracket), NodeKind::LeftBrace => Some(Category::Bracket),
NodeKind::RightBrace => Some(Category::Bracket), NodeKind::RightBrace => Some(Category::Bracket),
NodeKind::LeftBracket => Some(Category::Bracket),
NodeKind::RightBracket => Some(Category::Bracket),
NodeKind::LeftParen => Some(Category::Bracket), NodeKind::LeftParen => Some(Category::Bracket),
NodeKind::RightParen => Some(Category::Bracket), NodeKind::RightParen => Some(Category::Bracket),
NodeKind::Comma => Some(Category::Punctuation), NodeKind::Comma => Some(Category::Punctuation),
@ -176,13 +176,13 @@ impl Category {
NodeKind::Auto => Some(Category::Auto), NodeKind::Auto => Some(Category::Auto),
NodeKind::Ident(_) => match parent.kind() { NodeKind::Ident(_) => match parent.kind() {
NodeKind::Named => None, NodeKind::Named => None,
NodeKind::Closure if child.span().start == parent.span().start => { NodeKind::ClosureExpr if child.span().start == parent.span().start => {
Some(Category::Function) Some(Category::Function)
} }
NodeKind::WithExpr => Some(Category::Function), NodeKind::WithExpr => Some(Category::Function),
NodeKind::SetExpr => Some(Category::Function), NodeKind::SetExpr => Some(Category::Function),
NodeKind::ShowExpr => Some(Category::Function), NodeKind::ShowExpr => Some(Category::Function),
NodeKind::Call => Some(Category::Function), NodeKind::CallExpr => Some(Category::Function),
_ => Some(Category::Variable), _ => Some(Category::Variable),
}, },
NodeKind::Bool(_) => Some(Category::Bool), NodeKind::Bool(_) => Some(Category::Bool),
@ -202,18 +202,18 @@ impl Category {
NodeKind::TextInLine(_) => None, NodeKind::TextInLine(_) => None,
NodeKind::List => None, NodeKind::List => None,
NodeKind::Enum => None, NodeKind::Enum => None,
NodeKind::Array => None, NodeKind::CodeBlock => None,
NodeKind::Dict => None, NodeKind::TemplateBlock => None,
NodeKind::GroupExpr => None,
NodeKind::ArrayExpr => None,
NodeKind::DictExpr => None,
NodeKind::Named => None, NodeKind::Named => None,
NodeKind::Template => None, NodeKind::UnaryExpr => None,
NodeKind::Group => None, NodeKind::BinaryExpr => None,
NodeKind::Block => None, NodeKind::CallExpr => None,
NodeKind::Unary => None,
NodeKind::Binary => None,
NodeKind::Call => None,
NodeKind::CallArgs => None, NodeKind::CallArgs => None,
NodeKind::Spread => None, NodeKind::Spread => None,
NodeKind::Closure => None, NodeKind::ClosureExpr => None,
NodeKind::ClosureParams => None, NodeKind::ClosureParams => None,
NodeKind::WithExpr => None, NodeKind::WithExpr => None,
NodeKind::LetExpr => None, NodeKind::LetExpr => None,

View File

@ -481,14 +481,14 @@ impl ExactSizeIterator for Children<'_> {}
/// the parser. /// the parser.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum NodeKind { pub enum NodeKind {
/// A left square bracket: `[`.
LeftBracket,
/// A right square bracket: `]`.
RightBracket,
/// A left curly brace: `{`. /// A left curly brace: `{`.
LeftBrace, LeftBrace,
/// A right curly brace: `}`. /// A right curly brace: `}`.
RightBrace, RightBrace,
/// A left square bracket: `[`.
LeftBracket,
/// A right square bracket: `]`.
RightBracket,
/// A left round parenthesis: `(`. /// A left round parenthesis: `(`.
LeftParen, LeftParen,
/// A right round parenthesis: `)`. /// A right round parenthesis: `)`.
@ -642,30 +642,30 @@ pub enum NodeKind {
Fraction(f64), Fraction(f64),
/// A quoted string: `"..."`. /// A quoted string: `"..."`.
Str(EcoString), 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)`. /// An array expression: `(1, "hi", 12cm)`.
Array, ArrayExpr,
/// A dictionary expression: `(thickness: 3pt, pattern: dashed)`. /// A dictionary expression: `(thickness: 3pt, pattern: dashed)`.
Dict, DictExpr,
/// A named pair: `thickness: 3pt`. /// A named pair: `thickness: 3pt`.
Named, 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`. /// A unary operation: `-x`.
Unary, UnaryExpr,
/// A binary operation: `a + b`. /// A binary operation: `a + b`.
Binary, BinaryExpr,
/// An invocation of a function: `f(x, y)`. /// An invocation of a function: `f(x, y)`.
Call, CallExpr,
/// A function call's argument list: `(x, y)`. /// A function call's argument list: `(x, y)`.
CallArgs, CallArgs,
/// Spreaded arguments or a parameter sink: `..x`. /// Spreaded arguments or a parameter sink: `..x`.
Spread, Spread,
/// A closure expression: `(x, y) => z`. /// A closure expression: `(x, y) => z`.
Closure, ClosureExpr,
/// A closure's parameters: `(x, y)`. /// A closure's parameters: `(x, y)`.
ClosureParams, ClosureParams,
/// A with expression: `f with (x, y: 1)`. /// A with expression: `f with (x, y: 1)`.
@ -724,16 +724,16 @@ pub enum ErrorPos {
} }
impl NodeKind { 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. /// Whether this is some kind of brace.
pub fn is_brace(&self) -> bool { pub fn is_brace(&self) -> bool {
matches!(self, Self::LeftBrace | Self::RightBrace) 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. /// Whether this is some kind of parenthesis.
pub fn is_paren(&self) -> bool { pub fn is_paren(&self) -> bool {
matches!(self, Self::LeftParen | Self::RightParen) matches!(self, Self::LeftParen | Self::RightParen)
@ -782,10 +782,10 @@ impl NodeKind {
| Self::List | Self::List
| Self::Raw(_) | Self::Raw(_)
| Self::Math(_) => Some(TokenMode::Markup), | Self::Math(_) => Some(TokenMode::Markup),
Self::Template Self::TemplateBlock
| Self::Space(_) | Self::Space(_)
| Self::Block
| Self::Ident(_) | Self::Ident(_)
| Self::CodeBlock
| Self::LetExpr | Self::LetExpr
| Self::SetExpr | Self::SetExpr
| Self::ShowExpr | Self::ShowExpr
@ -794,7 +794,7 @@ impl NodeKind {
| Self::WhileExpr | Self::WhileExpr
| Self::ForExpr | Self::ForExpr
| Self::ImportExpr | Self::ImportExpr
| Self::Call | Self::CallExpr
| Self::IncludeExpr | Self::IncludeExpr
| Self::LineComment | Self::LineComment
| Self::BlockComment | Self::BlockComment
@ -808,10 +808,10 @@ impl NodeKind {
/// A human-readable name for the kind. /// A human-readable name for the kind.
pub fn as_str(&self) -> &'static str { pub fn as_str(&self) -> &'static str {
match self { match self {
Self::LeftBracket => "opening bracket",
Self::RightBracket => "closing bracket",
Self::LeftBrace => "opening brace", Self::LeftBrace => "opening brace",
Self::RightBrace => "closing brace", Self::RightBrace => "closing brace",
Self::LeftBracket => "opening bracket",
Self::RightBracket => "closing bracket",
Self::LeftParen => "opening paren", Self::LeftParen => "opening paren",
Self::RightParen => "closing paren", Self::RightParen => "closing paren",
Self::Star => "star", Self::Star => "star",
@ -883,18 +883,18 @@ impl NodeKind {
Self::Percentage(_) => "percentage", Self::Percentage(_) => "percentage",
Self::Fraction(_) => "`fr` value", Self::Fraction(_) => "`fr` value",
Self::Str(_) => "string", Self::Str(_) => "string",
Self::Array => "array", Self::CodeBlock => "code block",
Self::Dict => "dictionary", Self::TemplateBlock => "template block",
Self::GroupExpr => "group",
Self::ArrayExpr => "array",
Self::DictExpr => "dictionary",
Self::Named => "named argument", Self::Named => "named argument",
Self::Template => "template", Self::UnaryExpr => "unary expression",
Self::Group => "group", Self::BinaryExpr => "binary expression",
Self::Block => "block", Self::CallExpr => "call",
Self::Unary => "unary expression",
Self::Binary => "binary expression",
Self::Call => "call",
Self::CallArgs => "call arguments", Self::CallArgs => "call arguments",
Self::Spread => "parameter sink", Self::Spread => "parameter sink",
Self::Closure => "closure", Self::ClosureExpr => "closure",
Self::ClosureParams => "closure parameters", Self::ClosureParams => "closure parameters",
Self::WithExpr => "`with` expression", Self::WithExpr => "`with` expression",
Self::LetExpr => "`let` expression", Self::LetExpr => "`let` expression",
@ -932,10 +932,10 @@ impl Hash for NodeKind {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
std::mem::discriminant(self).hash(state); std::mem::discriminant(self).hash(state);
match self { match self {
Self::LeftBracket => {}
Self::RightBracket => {}
Self::LeftBrace => {} Self::LeftBrace => {}
Self::RightBrace => {} Self::RightBrace => {}
Self::LeftBracket => {}
Self::RightBracket => {}
Self::LeftParen => {} Self::LeftParen => {}
Self::RightParen => {} Self::RightParen => {}
Self::Star => {} Self::Star => {}
@ -1007,18 +1007,18 @@ impl Hash for NodeKind {
Self::Percentage(v) => v.to_bits().hash(state), Self::Percentage(v) => v.to_bits().hash(state),
Self::Fraction(v) => v.to_bits().hash(state), Self::Fraction(v) => v.to_bits().hash(state),
Self::Str(v) => v.hash(state), Self::Str(v) => v.hash(state),
Self::Array => {} Self::CodeBlock => {}
Self::Dict => {} Self::TemplateBlock => {}
Self::GroupExpr => {}
Self::ArrayExpr => {}
Self::DictExpr => {}
Self::Named => {} Self::Named => {}
Self::Template => {} Self::UnaryExpr => {}
Self::Group => {} Self::BinaryExpr => {}
Self::Block => {} Self::CallExpr => {}
Self::Unary => {}
Self::Binary => {}
Self::Call => {}
Self::CallArgs => {} Self::CallArgs => {}
Self::Spread => {} Self::Spread => {}
Self::Closure => {} Self::ClosureExpr => {}
Self::ClosureParams => {} Self::ClosureParams => {}
Self::WithExpr => {} Self::WithExpr => {}
Self::LetExpr => {} Self::LetExpr => {}