diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-10-17 16:47:07 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-10-17 17:11:01 +0200 |
| commit | 4fd031a256b2ecfe524859d5599fafb386395572 (patch) | |
| tree | 14787137b5188666a2133525d10ac0b72357551c /src/syntax | |
| parent | 54b38c479060ac06213cb311f22b84bccdf88932 (diff) | |
More spans in AST
Diffstat (limited to 'src/syntax')
| -rw-r--r-- | src/syntax/ast.rs | 823 | ||||
| -rw-r--r-- | src/syntax/highlight.rs | 114 | ||||
| -rw-r--r-- | src/syntax/kind.rs | 335 |
3 files changed, 727 insertions, 545 deletions
diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs index aa590da2..ecfa9a5b 100644 --- a/src/syntax/ast.rs +++ b/src/syntax/ast.rs @@ -5,8 +5,7 @@ use std::num::NonZeroUsize; use std::ops::Deref; -use super::{NodeData, NodeKind, Span, SyntaxNode}; -use crate::geom::{AngleUnit, LengthUnit}; +use super::{NodeData, NodeKind, RawKind, Span, SyntaxNode, Unit}; use crate::util::EcoString; /// A typed AST node. @@ -25,10 +24,7 @@ pub trait TypedNode: Sized { macro_rules! node { ($(#[$attr:meta])* $name:ident) => { - node!{$(#[$attr])* $name: $name} - }; - ($(#[$attr:meta])* $name:ident: $variant:ident) => { - node!{$(#[$attr])* $name: NodeKind::$variant} + node!{ $(#[$attr])* $name: NodeKind::$name { .. } } }; ($(#[$attr:meta])* $name:ident: $variants:pat) => { #[derive(Debug, Clone, PartialEq, Hash)] @@ -54,254 +50,296 @@ macro_rules! node { node! { /// The syntactical root capable of representing a full parsed document. - MarkupNode: NodeKind::Markup { .. } + Markup } -impl MarkupNode { +impl Markup { /// The children. - pub fn items(&self) -> impl Iterator<Item = MarkupItem> + '_ { + pub fn children(&self) -> impl Iterator<Item = MarkupNode> + '_ { self.0.children().filter_map(SyntaxNode::cast) } } /// A single piece of markup. #[derive(Debug, Clone, PartialEq)] -pub enum MarkupItem { +pub enum MarkupNode { /// Whitespace containing less than two newlines. - Space, + Space(Space), /// A forced line break. - Linebreak, - /// A paragraph break: Two or more newlines. - Parbreak, + Linebreak(Linebreak), /// Plain text. - Text(EcoString), + Text(Text), + /// An escape sequence: `\#`, `\u{1F5FA}`. + Escape(Escape), + /// A shorthand for a unicode codepoint. For example, `~` for non-breaking + /// space or `-?` for a soft hyphen. + Shorthand(Shorthand), /// A smart quote: `'` or `"`. - Quote { double: bool }, - /// Strong content: `*Strong*`. - Strong(StrongNode), - /// Emphasized content: `_Emphasized_`. - Emph(EmphNode), - /// A hyperlink: `https://typst.org`. - Link(EcoString), + SmartQuote(SmartQuote), + /// Strong markup: `*Strong*`. + Strong(Strong), + /// Emphasized markup: `_Emphasized_`. + Emph(Emph), /// A raw block with optional syntax highlighting: `` `...` ``. - Raw(RawNode), - /// A math formula: `$x$`, `$ x^2 $`. - Math(MathNode), + Raw(Raw), + /// A hyperlink: `https://typst.org`. + Link(Link), + /// A label: `<label>`. + Label(Label), + /// A reference: `@target`. + Ref(Ref), /// A section heading: `= Introduction`. - Heading(HeadingNode), + Heading(Heading), /// An item in an unordered list: `- ...`. List(ListItem), /// An item in an enumeration (ordered list): `+ ...` or `1. ...`. Enum(EnumItem), /// An item in a description list: `/ Term: Details`. Desc(DescItem), - /// A label: `<label>`. - Label(EcoString), - /// A reference: `@label`. - Ref(EcoString), + /// A math formula: `$x$`, `$ x^2 $`. + Math(Math), /// An expression. Expr(Expr), } -impl TypedNode for MarkupItem { +impl TypedNode for MarkupNode { fn from_untyped(node: &SyntaxNode) -> Option<Self> { match node.kind() { - NodeKind::Space { newlines: (2 ..) } => Some(Self::Parbreak), - NodeKind::Space { .. } => Some(Self::Space), - NodeKind::Backslash => Some(Self::Linebreak), - NodeKind::Text(s) => Some(Self::Text(s.clone())), - NodeKind::Escape(c) => Some(Self::Text((*c).into())), - NodeKind::Tilde => Some(Self::Text('\u{00A0}'.into())), - NodeKind::HyphQuest => Some(Self::Text('\u{00AD}'.into())), - NodeKind::Hyph2 => Some(Self::Text('\u{2013}'.into())), - NodeKind::Hyph3 => Some(Self::Text('\u{2014}'.into())), - NodeKind::Dot3 => Some(Self::Text('\u{2026}'.into())), - NodeKind::Quote { double } => Some(Self::Quote { double: *double }), + NodeKind::Space { .. } => node.cast().map(Self::Space), + NodeKind::Linebreak => node.cast().map(Self::Linebreak), + NodeKind::Text(_) => node.cast().map(Self::Text), + NodeKind::Escape(_) => node.cast().map(Self::Escape), + NodeKind::Shorthand(_) => node.cast().map(Self::Shorthand), + NodeKind::SmartQuote { .. } => node.cast().map(Self::SmartQuote), NodeKind::Strong => node.cast().map(Self::Strong), NodeKind::Emph => node.cast().map(Self::Emph), - NodeKind::Link(url) => Some(Self::Link(url.clone())), - NodeKind::Raw(raw) => Some(Self::Raw(raw.as_ref().clone())), - NodeKind::Math => node.cast().map(Self::Math), + NodeKind::Raw(_) => node.cast().map(Self::Raw), + NodeKind::Link(_) => node.cast().map(Self::Link), + NodeKind::Label(_) => node.cast().map(Self::Label), + NodeKind::Ref(_) => node.cast().map(Self::Ref), NodeKind::Heading => node.cast().map(Self::Heading), NodeKind::ListItem => node.cast().map(Self::List), NodeKind::EnumItem => node.cast().map(Self::Enum), NodeKind::DescItem => node.cast().map(Self::Desc), - NodeKind::Label(v) => Some(Self::Label(v.clone())), - NodeKind::Ref(v) => Some(Self::Ref(v.clone())), + NodeKind::Math => node.cast().map(Self::Math), _ => node.cast().map(Self::Expr), } } fn as_untyped(&self) -> &SyntaxNode { - unimplemented!("MarkupNode::as_untyped") + match self { + Self::Space(v) => v.as_untyped(), + Self::Linebreak(v) => v.as_untyped(), + Self::Text(v) => v.as_untyped(), + Self::Escape(v) => v.as_untyped(), + Self::Shorthand(v) => v.as_untyped(), + Self::SmartQuote(v) => v.as_untyped(), + Self::Strong(v) => v.as_untyped(), + Self::Emph(v) => v.as_untyped(), + Self::Raw(v) => v.as_untyped(), + Self::Link(v) => v.as_untyped(), + Self::Label(v) => v.as_untyped(), + Self::Ref(v) => v.as_untyped(), + Self::Heading(v) => v.as_untyped(), + Self::List(v) => v.as_untyped(), + Self::Enum(v) => v.as_untyped(), + Self::Desc(v) => v.as_untyped(), + Self::Math(v) => v.as_untyped(), + Self::Expr(v) => v.as_untyped(), + } } } node! { - /// Strong content: `*Strong*`. - StrongNode: Strong + /// Whitespace. + Space } -impl StrongNode { - /// The contents of the strong node. - pub fn body(&self) -> MarkupNode { - self.0.cast_first_child().expect("strong node is missing markup body") +impl Space { + /// Get the number of newlines. + pub fn newlines(&self) -> usize { + match self.0.kind() { + &NodeKind::Space { newlines } => newlines, + _ => panic!("space is of wrong kind"), + } } } node! { - /// Emphasized content: `_Emphasized_`. - EmphNode: Emph + /// A forced line break. + Linebreak } -impl EmphNode { - /// The contents of the emphasis node. - pub fn body(&self) -> MarkupNode { - self.0 - .cast_first_child() - .expect("emphasis node is missing markup body") - } +node! { + /// Plain text. + Text } -/// A raw block with optional syntax highlighting: `` `...` ``. -#[derive(Debug, Clone, PartialEq, Hash)] -pub struct RawNode { - /// An optional identifier specifying the language to syntax-highlight in. - pub lang: Option<EcoString>, - /// The raw text, determined as the raw string between the backticks trimmed - /// according to the above rules. - pub text: EcoString, - /// Whether the element is block-level, that is, it has 3+ backticks - /// and contains at least one newline. - pub block: bool, +impl Text { + /// Get the text. + pub fn get(&self) -> &EcoString { + match self.0.kind() { + NodeKind::Text(v) => v, + _ => panic!("text is of wrong kind"), + } + } } node! { - /// A math formula: `$x$`, `$ x^2 $`. - MathNode: NodeKind::Math { .. } + /// An escape sequence: `\#`, `\u{1F5FA}`. + Escape } -impl MathNode { - /// The children. - pub fn items(&self) -> impl Iterator<Item = MathItem> + '_ { - self.0.children().filter_map(SyntaxNode::cast) +impl Escape { + /// Get the escaped character. + pub fn get(&self) -> char { + match self.0.kind() { + &NodeKind::Escape(v) => v, + _ => panic!("escape is of wrong kind"), + } } } -/// A single piece of a math formula. -#[derive(Debug, Clone, PartialEq, Hash)] -pub enum MathItem { - /// Whitespace. - Space, - /// A forced line break. - Linebreak, - /// An atom: `x`, `+`, `12`. - Atom(EcoString), - /// A base with an optional sub- and superscript: `a_1^2`. - Script(ScriptNode), - /// A fraction: `x/2`. - Frac(FracNode), - /// An alignment indicator: `&`, `&&`. - Align(AlignNode), - /// Grouped mathematical material. - Group(MathNode), - /// An expression. - Expr(Expr), +node! { + /// A shorthand for a unicode codepoint. For example, `~` for non-breaking + /// space or `-?` for a soft hyphen. + Shorthand } -impl TypedNode for MathItem { - fn from_untyped(node: &SyntaxNode) -> Option<Self> { - match node.kind() { - NodeKind::Space { .. } => Some(Self::Space), - NodeKind::LeftBrace => Some(Self::Atom('{'.into())), - NodeKind::RightBrace => Some(Self::Atom('}'.into())), - NodeKind::LeftBracket => Some(Self::Atom('['.into())), - NodeKind::RightBracket => Some(Self::Atom(']'.into())), - NodeKind::LeftParen => Some(Self::Atom('('.into())), - NodeKind::RightParen => Some(Self::Atom(')'.into())), - NodeKind::Backslash => Some(Self::Linebreak), - NodeKind::Escape(c) => Some(Self::Atom((*c).into())), - NodeKind::Atom(atom) => Some(Self::Atom(atom.clone())), - NodeKind::Script => node.cast().map(Self::Script), - NodeKind::Frac => node.cast().map(Self::Frac), - NodeKind::Align => node.cast().map(Self::Align), - NodeKind::Math => node.cast().map(Self::Group), - _ => node.cast().map(Self::Expr), +impl Shorthand { + /// Get the shorthanded character. + pub fn get(&self) -> char { + match self.0.kind() { + &NodeKind::Shorthand(v) => v, + _ => panic!("shorthand is of wrong kind"), } } +} - fn as_untyped(&self) -> &SyntaxNode { - unimplemented!("MathNode::as_untyped") +node! { + /// A smart quote: `'` or `"`. + SmartQuote +} + +impl SmartQuote { + /// Whether this is a double quote. + pub fn double(&self) -> bool { + match self.0.kind() { + &NodeKind::SmartQuote { double } => double, + _ => panic!("smart quote is of wrong kind"), + } } } node! { - /// A base with an optional sub- and superscript in a formula: `a_1^2`. - ScriptNode: Script + /// Strong content: `*Strong*`. + Strong } -impl ScriptNode { - /// The base of the script. - pub fn base(&self) -> MathItem { - self.0.cast_first_child().expect("subscript is missing base") +impl Strong { + /// The contents of the strong node. + pub fn body(&self) -> Markup { + self.0.cast_first_child().expect("strong node is missing markup body") } +} - /// The subscript. - pub fn sub(&self) -> Option<MathItem> { +node! { + /// Emphasized content: `_Emphasized_`. + Emph +} + +impl Emph { + /// The contents of the emphasis node. + pub fn body(&self) -> Markup { self.0 - .children() - .skip_while(|node| !matches!(node.kind(), NodeKind::Underscore)) - .nth(1) - .map(|node| node.cast().expect("script node has invalid subscript")) + .cast_first_child() + .expect("emphasis node is missing markup body") } +} - /// The superscript. - pub fn sup(&self) -> Option<MathItem> { - self.0 - .children() - .skip_while(|node| !matches!(node.kind(), NodeKind::Hat)) - .nth(1) - .map(|node| node.cast().expect("script node has invalid superscript")) +node! { + /// A raw block with optional syntax highlighting: `` `...` ``. + Raw +} + +impl Raw { + /// The raw text. + pub fn text(&self) -> &EcoString { + &self.get().text + } + + /// An optional identifier specifying the language to syntax-highlight in. + pub fn lang(&self) -> Option<&EcoString> { + self.get().lang.as_ref() + } + + /// Whether the raw block is block-level. + pub fn block(&self) -> bool { + self.get().block + } + + /// The raw fields. + fn get(&self) -> &RawKind { + match self.0.kind() { + NodeKind::Raw(v) => v.as_ref(), + _ => panic!("raw is of wrong kind"), + } } } node! { - /// A fraction in a formula: `x/2` - FracNode: Frac + /// A hyperlink: `https://typst.org`. + Link } -impl FracNode { - /// The numerator. - pub fn num(&self) -> MathItem { - self.0.cast_first_child().expect("fraction is missing numerator") +impl Link { + /// Get the URL. + pub fn url(&self) -> &EcoString { + match self.0.kind() { + NodeKind::Link(url) => url, + _ => panic!("link is of wrong kind"), + } } +} - /// The denominator. - pub fn denom(&self) -> MathItem { - self.0.cast_last_child().expect("fraction is missing denominator") +node! { + /// A label: `<label>`. + Label +} + +impl Label { + /// Get the label. + pub fn get(&self) -> &EcoString { + match self.0.kind() { + NodeKind::Label(v) => v, + _ => panic!("label is of wrong kind"), + } } } node! { - /// A math alignment indicator: `&`, `&&`. - AlignNode: Align + /// A reference: `@target`. + Ref } -impl AlignNode { - /// The number of ampersands. - pub fn count(&self) -> usize { - self.0.children().filter(|n| n.kind() == &NodeKind::Amp).count() +impl Ref { + /// Get the target. + pub fn get(&self) -> &EcoString { + match self.0.kind() { + NodeKind::Ref(v) => v, + _ => panic!("reference is of wrong kind"), + } } } node! { /// A section heading: `= Introduction`. - HeadingNode: Heading + Heading } -impl HeadingNode { +impl Heading { /// The contents of the heading. - pub fn body(&self) -> MarkupNode { + pub fn body(&self) -> Markup { self.0.cast_first_child().expect("heading is missing markup body") } @@ -318,19 +356,19 @@ impl HeadingNode { node! { /// An item in an unordered list: `- ...`. - ListItem: ListItem + ListItem } impl ListItem { /// The contents of the list item. - pub fn body(&self) -> MarkupNode { + pub fn body(&self) -> Markup { self.0.cast_first_child().expect("list item is missing body") } } node! { /// An item in an enumeration (ordered list): `1. ...`. - EnumItem: EnumItem + EnumItem } impl EnumItem { @@ -343,32 +381,171 @@ impl EnumItem { } /// The contents of the list item. - pub fn body(&self) -> MarkupNode { + pub fn body(&self) -> Markup { self.0.cast_first_child().expect("enum item is missing body") } } node! { /// An item in a description list: `/ Term: Details`. - DescItem: DescItem + DescItem } impl DescItem { /// The term described by the item. - pub fn term(&self) -> MarkupNode { + pub fn term(&self) -> Markup { self.0 .cast_first_child() .expect("description list item is missing term") } /// The description of the term. - pub fn body(&self) -> MarkupNode { + pub fn body(&self) -> Markup { self.0 .cast_last_child() .expect("description list item is missing body") } } +node! { + /// A math formula: `$x$`, `$ x^2 $`. + Math +} + +impl Math { + /// The children. + pub fn children(&self) -> impl Iterator<Item = MathNode> + '_ { + self.0.children().filter_map(SyntaxNode::cast) + } +} + +/// A single piece of a math formula. +#[derive(Debug, Clone, PartialEq, Hash)] +pub enum MathNode { + /// Whitespace. + Space(Space), + /// A forced line break. + Linebreak(Linebreak), + /// An escape sequence: `\#`, `\u{1F5FA}`. + Escape(Escape), + /// A atom: `x`, `+`, `12`. + Atom(Atom), + /// A base with an optional sub- and superscript: `a_1^2`. + Script(Script), + /// A fraction: `x/2`. + Frac(Frac), + /// An alignment indicator: `&`, `&&`. + Align(Align), + /// Grouped mathematical material. + Group(Math), + /// An expression. + Expr(Expr), +} + +impl TypedNode for MathNode { + fn from_untyped(node: &SyntaxNode) -> Option<Self> { + match node.kind() { + NodeKind::Space { .. } => node.cast().map(Self::Space), + NodeKind::Linebreak => node.cast().map(Self::Linebreak), + NodeKind::Escape(_) => node.cast().map(Self::Escape), + NodeKind::Atom(_) => node.cast().map(Self::Atom), + NodeKind::Script => node.cast().map(Self::Script), + NodeKind::Frac => node.cast().map(Self::Frac), + NodeKind::Align => node.cast().map(Self::Align), + NodeKind::Math => node.cast().map(Self::Group), + _ => node.cast().map(Self::Expr), + } + } + + fn as_untyped(&self) -> &SyntaxNode { + match self { + Self::Space(v) => v.as_untyped(), + Self::Linebreak(v) => v.as_untyped(), + Self::Escape(v) => v.as_untyped(), + Self::Atom(v) => v.as_untyped(), + Self::Script(v) => v.as_untyped(), + Self::Frac(v) => v.as_untyped(), + Self::Align(v) => v.as_untyped(), + Self::Group(v) => v.as_untyped(), + Self::Expr(v) => v.as_untyped(), + } + } +} + +node! { + /// A atom in a formula: `x`, `+`, `12`. + Atom +} + +impl Atom { + /// Get the atom's text. + pub fn get(&self) -> &EcoString { + match self.0.kind() { + NodeKind::Atom(v) => v, + _ => panic!("atom is of wrong kind"), + } + } +} + +node! { + /// A base with an optional sub- and superscript in a formula: `a_1^2`. + Script +} + +impl Script { + /// The base of the script. + pub fn base(&self) -> MathNode { + self.0.cast_first_child().expect("script node is missing base") + } + + /// The subscript. + pub fn sub(&self) -> Option<MathNode> { + self.0 + .children() + .skip_while(|node| !matches!(node.kind(), NodeKind::Underscore)) + .nth(1) + .map(|node| node.cast().expect("script node has invalid subscript")) + } + + /// The superscript. + pub fn sup(&self) -> Option<MathNode> { + self.0 + .children() + .skip_while(|node| !matches!(node.kind(), NodeKind::Hat)) + .nth(1) + .map(|node| node.cast().expect("script node has invalid superscript")) + } +} + +node! { + /// A fraction in a formula: `x/2` + Frac +} + +impl Frac { + /// The numerator. + pub fn num(&self) -> MathNode { + self.0.cast_first_child().expect("fraction is missing numerator") + } + + /// The denominator. + pub fn denom(&self) -> MathNode { + self.0.cast_last_child().expect("fraction is missing denominator") + } +} + +node! { + /// A math alignment indicator: `&`, `&&`. + Align +} + +impl Align { + /// The number of ampersands. + pub fn count(&self) -> usize { + self.0.children().filter(|n| n.kind() == &NodeKind::Amp).count() + } +} + /// An expression. #[derive(Debug, Clone, PartialEq, Hash)] pub enum Expr { @@ -381,15 +558,15 @@ pub enum Expr { /// A content block: `[*Hi* there!]`. Content(ContentBlock), /// A grouped expression: `(1 + 2)`. - Group(GroupExpr), + Parenthesized(Parenthesized), /// An array expression: `(1, "hi", 12cm)`. - Array(ArrayExpr), + Array(Array), /// A dictionary expression: `(thickness: 3pt, pattern: dashed)`. - Dict(DictExpr), + Dict(Dict), /// A unary operation: `-x`. - Unary(UnaryExpr), + Unary(Unary), /// A binary operation: `a + b`. - Binary(BinaryExpr), + Binary(Binary), /// A field access: `properties.age`. FieldAccess(FieldAccess), /// An invocation of a function: `f(x, y)`. @@ -397,31 +574,31 @@ pub enum Expr { /// An invocation of a method: `array.push(v)`. MethodCall(MethodCall), /// A closure expression: `(x, y) => z`. - Closure(ClosureExpr), - /// A let expression: `let x = 1`. - Let(LetExpr), - /// A set expression: `set text(...)`. - Set(SetExpr), - /// A show expression: `show node: heading as [*{nody.body}*]`. - Show(ShowExpr), - /// A wrap expression: `wrap body in columns(2, body)`. - Wrap(WrapExpr), - /// 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), - /// A break expression: `break`. - Break(BreakExpr), - /// A continue expression: `continue`. - Continue(ContinueExpr), - /// A return expression: `return`. - Return(ReturnExpr), + Closure(Closure), + /// A let binding: `let x = 1`. + Let(LetBinding), + /// A set rule: `set text(...)`. + Set(SetRule), + /// A show rule: `show node: heading as [*{nody.body}*]`. + Show(ShowRule), + /// A wrap rule: `wrap body in columns(2, body)`. + Wrap(WrapRule), + /// An if-else conditional: `if x { y } else { z }`. + Conditional(Conditional), + /// A while loop: `while x { y }`. + While(WhileLoop), + /// A for loop: `for x in y { z }`. + For(ForLoop), + /// A module import: `import a, b, c from "utils.typ"`. + Import(ModuleImport), + /// A module include: `include "chapter1.typ"`. + Include(ModuleInclude), + /// A break statement: `break`. + Break(BreakStmt), + /// A continue statement: `continue`. + Continue(ContinueStmt), + /// A return statement: `return`, `return x + 1`. + Return(ReturnStmt), } impl TypedNode for Expr { @@ -430,27 +607,27 @@ impl TypedNode for Expr { NodeKind::Ident(_) => node.cast().map(Self::Ident), NodeKind::CodeBlock => node.cast().map(Self::Code), NodeKind::ContentBlock => node.cast().map(Self::Content), - 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::Parenthesized => node.cast().map(Self::Parenthesized), + NodeKind::Array => node.cast().map(Self::Array), + NodeKind::Dict => node.cast().map(Self::Dict), + NodeKind::Unary => node.cast().map(Self::Unary), + NodeKind::Binary => node.cast().map(Self::Binary), NodeKind::FieldAccess => node.cast().map(Self::FieldAccess), NodeKind::FuncCall => node.cast().map(Self::FuncCall), NodeKind::MethodCall => node.cast().map(Self::MethodCall), - NodeKind::ClosureExpr => node.cast().map(Self::Closure), - NodeKind::LetExpr => node.cast().map(Self::Let), - NodeKind::SetExpr => node.cast().map(Self::Set), - NodeKind::ShowExpr => node.cast().map(Self::Show), - NodeKind::WrapExpr => node.cast().map(Self::Wrap), - NodeKind::IfExpr => node.cast().map(Self::If), - NodeKind::WhileExpr => node.cast().map(Self::While), - NodeKind::ForExpr => node.cast().map(Self::For), - NodeKind::ImportExpr => node.cast().map(Self::Import), - NodeKind::IncludeExpr => node.cast().map(Self::Include), - NodeKind::BreakExpr => node.cast().map(Self::Break), - NodeKind::ContinueExpr => node.cast().map(Self::Continue), - NodeKind::ReturnExpr => node.cast().map(Self::Return), + NodeKind::Closure => node.cast().map(Self::Closure), + NodeKind::LetBinding => node.cast().map(Self::Let), + NodeKind::SetRule => node.cast().map(Self::Set), + NodeKind::ShowRule => node.cast().map(Self::Show), + NodeKind::WrapRule => node.cast().map(Self::Wrap), + NodeKind::Conditional => node.cast().map(Self::Conditional), + NodeKind::WhileLoop => node.cast().map(Self::While), + NodeKind::ForLoop => node.cast().map(Self::For), + NodeKind::ModuleImport => node.cast().map(Self::Import), + NodeKind::ModuleInclude => node.cast().map(Self::Include), + NodeKind::BreakStmt => node.cast().map(Self::Break), + NodeKind::ContinueStmt => node.cast().map(Self::Continue), + NodeKind::ReturnStmt => node.cast().map(Self::Return), _ => node.cast().map(Self::Lit), } } @@ -463,7 +640,7 @@ impl TypedNode for Expr { Self::Ident(v) => v.as_untyped(), Self::Array(v) => v.as_untyped(), Self::Dict(v) => v.as_untyped(), - Self::Group(v) => v.as_untyped(), + Self::Parenthesized(v) => v.as_untyped(), Self::Unary(v) => v.as_untyped(), Self::Binary(v) => v.as_untyped(), Self::FieldAccess(v) => v.as_untyped(), @@ -474,7 +651,7 @@ impl TypedNode for Expr { Self::Set(v) => v.as_untyped(), Self::Show(v) => v.as_untyped(), Self::Wrap(v) => v.as_untyped(), - Self::If(v) => v.as_untyped(), + Self::Conditional(v) => v.as_untyped(), Self::While(v) => v.as_untyped(), Self::For(v) => v.as_untyped(), Self::Import(v) => v.as_untyped(), @@ -497,7 +674,7 @@ impl Expr { | Self::Set(_) | Self::Show(_) | Self::Wrap(_) - | Self::If(_) + | Self::Conditional(_) | Self::While(_) | Self::For(_) | Self::Import(_) @@ -552,24 +729,9 @@ pub enum LitKind { Str(EcoString), } -/// Unit of a numeric value. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Unit { - /// An absolute length unit. - Length(LengthUnit), - /// An angular unit. - Angle(AngleUnit), - /// Font-relative: `1em` is the same as the font size. - Em, - /// Fractions: `fr`. - Fr, - /// Percentage: `%`. - Percent, -} - node! { /// A code block: `{ let x = 1; x + 2 }`. - CodeBlock: CodeBlock + CodeBlock } impl CodeBlock { @@ -581,46 +743,48 @@ impl CodeBlock { node! { /// A content block: `[*Hi* there!]`. - ContentBlock: ContentBlock + ContentBlock } impl ContentBlock { /// The contained markup. - pub fn body(&self) -> MarkupNode { - self.0.cast_first_child().expect("content is missing body") + pub fn body(&self) -> Markup { + self.0.cast_first_child().expect("content block is missing body") } } node! { - /// A grouped expression: `(1 + 2)`. - GroupExpr: GroupExpr + /// A parenthesized expression: `(1 + 2)`. + Parenthesized } -impl GroupExpr { +impl Parenthesized { /// The wrapped expression. pub fn expr(&self) -> Expr { - self.0.cast_first_child().expect("group is missing expression") + self.0 + .cast_first_child() + .expect("parenthesized expression is missing expression") } } node! { - /// An array expression: `(1, "hi", 12cm)`. - ArrayExpr: ArrayExpr + /// An array: `(1, "hi", 12cm)`. + Array } -impl ArrayExpr { - /// The array items. +impl Array { + /// The array's items. pub fn items(&self) -> impl Iterator<Item = ArrayItem> + '_ { self.0.children().filter_map(SyntaxNode::cast) } } -/// An item in an array expresssion. +/// An item in an array. #[derive(Debug, Clone, PartialEq, Hash)] pub enum ArrayItem { - /// A bare value: `12`. + /// A bare expression: `12`. Pos(Expr), - /// A spreaded value: `..things`. + /// A spreaded expression: `..things`. Spread(Expr), } @@ -641,12 +805,12 @@ impl TypedNode for ArrayItem { } node! { - /// A dictionary expression: `(thickness: 3pt, pattern: dashed)`. - DictExpr: DictExpr + /// A dictionary: `(thickness: 3pt, pattern: dashed)`. + Dict } -impl DictExpr { - /// The named dictionary items. +impl Dict { + /// The dictionary's items. pub fn items(&self) -> impl Iterator<Item = DictItem> + '_ { self.0.children().filter_map(SyntaxNode::cast) } @@ -659,7 +823,7 @@ pub enum DictItem { Named(Named), /// A keyed pair: `"spacy key": true`. Keyed(Keyed), - /// A spreaded value: `..things`. + /// A spreaded expression: `..things`. Spread(Expr), } @@ -724,21 +888,21 @@ impl Keyed { node! { /// A unary operation: `-x`. - UnaryExpr: UnaryExpr + Unary } -impl UnaryExpr { +impl Unary { /// The operator: `-`. pub fn op(&self) -> UnOp { self.0 .children() .find_map(|node| UnOp::from_token(node.kind())) - .expect("unary expression is missing operator") + .expect("unary operation is missing operator") } /// The expression to operate on: `x`. pub fn expr(&self) -> Expr { - self.0.cast_last_child().expect("unary expression is missing child") + self.0.cast_last_child().expect("unary operation is missing child") } } @@ -784,10 +948,10 @@ impl UnOp { node! { /// A binary operation: `a + b`. - BinaryExpr: BinaryExpr + Binary } -impl BinaryExpr { +impl Binary { /// The binary operator: `+`. pub fn op(&self) -> BinOp { let mut not = false; @@ -801,21 +965,21 @@ impl BinaryExpr { NodeKind::In if not => Some(BinOp::NotIn), _ => BinOp::from_token(node.kind()), }) - .expect("binary expression is missing operator") + .expect("binary operation is missing operator") } /// The left-hand side of the operation: `a`. pub fn lhs(&self) -> Expr { self.0 .cast_first_child() - .expect("binary expression is missing left-hand side") + .expect("binary operation is missing left-hand side") } /// The right-hand side of the operation: `b`. pub fn rhs(&self) -> Expr { self.0 .cast_last_child() - .expect("binary expression is missing right-hand side") + .expect("binary operation is missing right-hand side") } } @@ -975,24 +1139,24 @@ pub enum Assoc { node! { /// A field access: `properties.age`. - FieldAccess: FieldAccess + FieldAccess } impl FieldAccess { - /// The object with the field. - pub fn object(&self) -> Expr { + /// The expression to access the field on. + pub fn target(&self) -> Expr { self.0.cast_first_child().expect("field access is missing object") } /// The name of the field. pub fn field(&self) -> Ident { - self.0.cast_last_child().expect("field access call is missing name") + self.0.cast_last_child().expect("field access is missing name") } } node! { /// An invocation of a function: `f(x, y)`. - FuncCall: FuncCall + FuncCall } impl FuncCall { @@ -1002,7 +1166,7 @@ impl FuncCall { } /// The arguments to the function. - pub fn args(&self) -> CallArgs { + pub fn args(&self) -> Args { self.0 .cast_last_child() .expect("function call is missing argument list") @@ -1011,13 +1175,13 @@ impl FuncCall { node! { /// An invocation of a method: `array.push(v)`. - MethodCall: MethodCall + MethodCall } impl MethodCall { - /// The value to call the method on. - pub fn receiver(&self) -> Expr { - self.0.cast_first_child().expect("method call is missing callee") + /// The expresion to call the method on. + pub fn target(&self) -> Expr { + self.0.cast_first_child().expect("method call is missing target") } /// The name of the method. @@ -1026,7 +1190,7 @@ impl MethodCall { } /// The arguments to the method. - pub fn args(&self) -> CallArgs { + pub fn args(&self) -> Args { self.0 .cast_last_child() .expect("method call is missing argument list") @@ -1035,19 +1199,19 @@ impl MethodCall { node! { /// The arguments to a function: `12, draw: false`. - CallArgs + Args } -impl CallArgs { +impl Args { /// The positional and named arguments. - pub fn items(&self) -> impl Iterator<Item = CallArg> + '_ { + pub fn items(&self) -> impl Iterator<Item = Arg> + '_ { self.0.children().filter_map(SyntaxNode::cast) } } /// An argument to a function call. #[derive(Debug, Clone, PartialEq, Hash)] -pub enum CallArg { +pub enum Arg { /// A positional argument: `12`. Pos(Expr), /// A named argument: `draw: false`. @@ -1056,7 +1220,7 @@ pub enum CallArg { Spread(Expr), } -impl TypedNode for CallArg { +impl TypedNode for Arg { fn from_untyped(node: &SyntaxNode) -> Option<Self> { match node.kind() { NodeKind::Named => node.cast().map(Self::Named), @@ -1076,10 +1240,10 @@ impl TypedNode for CallArg { node! { /// A closure expression: `(x, y) => z`. - ClosureExpr: ClosureExpr + Closure } -impl ClosureExpr { +impl Closure { /// The name of the closure. /// /// This only exists if you use the function syntax sugar: `let f(x) = y`. @@ -1088,10 +1252,10 @@ impl ClosureExpr { } /// The parameter bindings. - pub fn params(&self) -> impl Iterator<Item = ClosureParam> + '_ { + pub fn params(&self) -> impl Iterator<Item = Param> + '_ { self.0 .children() - .find(|x| x.kind() == &NodeKind::ClosureParams) + .find(|x| x.kind() == &NodeKind::Params) .expect("closure is missing parameter list") .children() .filter_map(SyntaxNode::cast) @@ -1105,7 +1269,7 @@ impl ClosureExpr { /// A parameter to a closure. #[derive(Debug, Clone, PartialEq, Hash)] -pub enum ClosureParam { +pub enum Param { /// A positional parameter: `x`. Pos(Ident), /// A named parameter with a default value: `draw: false`. @@ -1114,7 +1278,7 @@ pub enum ClosureParam { Sink(Ident), } -impl TypedNode for ClosureParam { +impl TypedNode for Param { fn from_untyped(node: &SyntaxNode) -> Option<Self> { match node.kind() { NodeKind::Ident(_) => node.cast().map(Self::Pos), @@ -1134,11 +1298,11 @@ impl TypedNode for ClosureParam { } node! { - /// A let expression: `let x = 1`. - LetExpr + /// A let binding: `let x = 1`. + LetBinding } -impl LetExpr { +impl LetBinding { /// The binding to assign to. pub fn binding(&self) -> Ident { match self.0.cast_first_child() { @@ -1146,7 +1310,7 @@ impl LetExpr { Some(Expr::Closure(closure)) => { closure.name().expect("let-bound closure is missing name") } - _ => panic!("let expression is missing binding"), + _ => panic!("let is missing binding"), } } @@ -1163,28 +1327,28 @@ impl LetExpr { } node! { - /// A set expression: `set text(...)`. - SetExpr + /// A set rule: `set text(...)`. + SetRule } -impl SetExpr { +impl SetRule { /// The function to set style properties for. pub fn target(&self) -> Ident { self.0.cast_first_child().expect("set rule is missing target") } /// The style properties to set. - pub fn args(&self) -> CallArgs { + pub fn args(&self) -> Args { self.0.cast_last_child().expect("set rule is missing argument list") } } node! { - /// A show expression: `show node: heading as [*{nody.body}*]`. - ShowExpr + /// A show rule: `show node: heading as [*{nody.body}*]`. + ShowRule } -impl ShowExpr { +impl ShowRule { /// The binding to assign to. pub fn binding(&self) -> Option<Ident> { let mut children = self.0.children(); @@ -1210,31 +1374,31 @@ impl ShowExpr { } node! { - /// A wrap expression: `wrap body in columns(2, body)`. - WrapExpr + /// A wrap rule: `wrap body in columns(2, body)`. + WrapRule } -impl WrapExpr { +impl WrapRule { /// The binding to assign the remaining markup to. pub fn binding(&self) -> Ident { - self.0.cast_first_child().expect("wrap expression is missing binding") + self.0.cast_first_child().expect("wrap rule is missing binding") } /// The expression to evaluate. pub fn body(&self) -> Expr { - self.0.cast_last_child().expect("wrap expression is missing body") + self.0.cast_last_child().expect("wrap rule is missing body") } } node! { - /// An if-else expression: `if x { y } else { z }`. - IfExpr + /// An if-else conditional: `if x { y } else { z }`. + Conditional } -impl IfExpr { +impl Conditional { /// The condition which selects the body to evaluate. pub fn condition(&self) -> Expr { - self.0.cast_first_child().expect("if expression is missing condition") + self.0.cast_first_child().expect("conditional is missing condition") } /// The expression to evaluate if the condition is true. @@ -1243,7 +1407,7 @@ impl IfExpr { .children() .filter_map(SyntaxNode::cast) .nth(1) - .expect("if expression is missing body") + .expect("conditional is missing body") } /// The expression to evaluate if the condition is false. @@ -1253,11 +1417,11 @@ impl IfExpr { } node! { - /// A while loop expression: `while x { y }`. - WhileExpr + /// A while loop: `while x { y }`. + WhileLoop } -impl WhileExpr { +impl WhileLoop { /// The condition which selects whether to evaluate the body. pub fn condition(&self) -> Expr { self.0.cast_first_child().expect("while loop is missing condition") @@ -1270,11 +1434,11 @@ impl WhileExpr { } node! { - /// A for loop expression: `for x in y { z }`. - ForExpr + /// A for loop: `for x in y { z }`. + ForLoop } -impl ForExpr { +impl ForLoop { /// The pattern to assign to. pub fn pattern(&self) -> ForPattern { self.0.cast_first_child().expect("for loop is missing pattern") @@ -1292,7 +1456,7 @@ impl ForExpr { } node! { - /// A for-in loop expression: `for x in y { z }`. + /// A for-in loop: `for x in y { z }`. ForPattern } @@ -1311,11 +1475,11 @@ impl ForPattern { } node! { - /// An import expression: `import a, b, c from "utils.typ"`. - ImportExpr + /// A module import: `import a, b, c from "utils.typ"`. + ModuleImport } -impl ImportExpr { +impl ModuleImport { /// The items to be imported. pub fn imports(&self) -> Imports { self.0 @@ -1328,12 +1492,12 @@ impl ImportExpr { } _ => None, }) - .expect("import is missing items") + .expect("module import is missing items") } /// The path to the file that should be imported. pub fn path(&self) -> Expr { - self.0.cast_last_child().expect("import is missing path") + self.0.cast_last_child().expect("module import is missing path") } } @@ -1347,33 +1511,33 @@ pub enum Imports { } node! { - /// An include expression: `include "chapter1.typ"`. - IncludeExpr + /// A module include: `include "chapter1.typ"`. + ModuleInclude } -impl IncludeExpr { +impl ModuleInclude { /// The path to the file that should be included. pub fn path(&self) -> Expr { - self.0.cast_last_child().expect("include is missing path") + self.0.cast_last_child().expect("module include is missing path") } } node! { /// A break expression: `break`. - BreakExpr + BreakStmt } node! { /// A continue expression: `continue`. - ContinueExpr + ContinueStmt } node! { /// A return expression: `return`, `return x + 1`. - ReturnExpr + ReturnStmt } -impl ReturnExpr { +impl ReturnStmt { /// The expression to return. pub fn body(&self) -> Option<Expr> { self.0.cast_last_child() @@ -1382,11 +1546,19 @@ impl ReturnExpr { node! { /// An identifier. - Ident: NodeKind::Ident(_) + Ident } impl Ident { - /// Take out the contained [`EcoString`]. + /// Get the identifier. + pub fn get(&self) -> &EcoString { + match self.0.kind() { + NodeKind::Ident(id) => id, + _ => panic!("identifier is of wrong kind"), + } + } + + /// Take out the container identifier. pub fn take(self) -> EcoString { match self.0 { SyntaxNode::Leaf(NodeData { kind: NodeKind::Ident(id), .. }) => id, @@ -1399,9 +1571,6 @@ impl Deref for Ident { type Target = str; fn deref(&self) -> &Self::Target { - match &self.0 { - SyntaxNode::Leaf(NodeData { kind: NodeKind::Ident(id), .. }) => id, - _ => panic!("identifier is of wrong kind"), - } + self.get() } } diff --git a/src/syntax/highlight.rs b/src/syntax/highlight.rs index 60d349d1..bfb36078 100644 --- a/src/syntax/highlight.rs +++ b/src/syntax/highlight.rs @@ -138,23 +138,21 @@ pub enum Category { /// An escape sequence. Escape, /// An easily typable shortcut to a unicode codepoint. - Shortcut, + Shorthand, /// A smart quote. - Quote, - /// Strong text. + SmartQuote, + /// Strong markup. Strong, - /// Emphasized text. + /// Emphasized markup. Emph, /// A hyperlink. Link, /// Raw text or code. Raw, - /// A full math formula. - Math, - /// The delimiters of a math formula. - MathDelimiter, - /// A symbol with special meaning in a math formula. - MathSymbol, + /// A label. + Label, + /// A reference. + Ref, /// A section heading. Heading, /// A full item of a list, enumeration or description list. @@ -163,10 +161,12 @@ pub enum Category { ListMarker, /// A term in a description list. ListTerm, - /// A label. - Label, - /// A reference. - Ref, + /// A full math formula. + Math, + /// The delimiters of a math formula. + MathDelimiter, + /// An operator with special meaning in a math formula. + MathOperator, /// A keyword. Keyword, /// A literal defined by a keyword like `none`, `auto` or a boolean. @@ -212,17 +212,10 @@ impl Category { _ => Some(Category::Operator), }, NodeKind::Underscore => match parent.kind() { - NodeKind::Script => Some(Category::MathSymbol), + NodeKind::Script => Some(Category::MathOperator), _ => None, }, NodeKind::Dollar => Some(Category::MathDelimiter), - NodeKind::Backslash => Some(Category::Shortcut), - NodeKind::Tilde => Some(Category::Shortcut), - NodeKind::HyphQuest => Some(Category::Shortcut), - NodeKind::Hyph2 => Some(Category::Shortcut), - NodeKind::Hyph3 => Some(Category::Shortcut), - NodeKind::Dot3 => Some(Category::Shortcut), - NodeKind::Quote { .. } => Some(Category::Quote), NodeKind::Plus => Some(match parent.kind() { NodeKind::EnumItem => Category::ListMarker, _ => Category::Operator, @@ -233,11 +226,11 @@ impl Category { }), NodeKind::Slash => Some(match parent.kind() { NodeKind::DescItem => Category::ListMarker, - NodeKind::Frac => Category::MathSymbol, + NodeKind::Frac => Category::MathOperator, _ => Category::Operator, }), - NodeKind::Hat => Some(Category::MathSymbol), - NodeKind::Amp => Some(Category::MathSymbol), + NodeKind::Hat => Some(Category::MathOperator), + NodeKind::Amp => Some(Category::MathOperator), NodeKind::Dot => Some(Category::Punctuation), NodeKind::Eq => match parent.kind() { NodeKind::Heading => None, @@ -291,32 +284,35 @@ impl Category { _ => None, }, NodeKind::Text(_) => None, + NodeKind::Linebreak => Some(Category::Escape), NodeKind::Escape(_) => Some(Category::Escape), + NodeKind::Shorthand(_) => Some(Category::Shorthand), + NodeKind::SmartQuote { .. } => Some(Category::SmartQuote), NodeKind::Strong => Some(Category::Strong), NodeKind::Emph => Some(Category::Emph), - NodeKind::Link(_) => Some(Category::Link), NodeKind::Raw(_) => Some(Category::Raw), - NodeKind::Math => Some(Category::Math), - NodeKind::Atom(_) => None, - NodeKind::Script => None, - NodeKind::Frac => None, - NodeKind::Align => None, + NodeKind::Link(_) => Some(Category::Link), + NodeKind::Label(_) => Some(Category::Label), + NodeKind::Ref(_) => Some(Category::Ref), NodeKind::Heading => Some(Category::Heading), NodeKind::ListItem => Some(Category::ListItem), NodeKind::EnumItem => Some(Category::ListItem), NodeKind::EnumNumbering(_) => Some(Category::ListMarker), NodeKind::DescItem => Some(Category::ListItem), - NodeKind::Label(_) => Some(Category::Label), - NodeKind::Ref(_) => Some(Category::Ref), + NodeKind::Math => Some(Category::Math), + NodeKind::Atom(_) => None, + NodeKind::Script => None, + NodeKind::Frac => None, + NodeKind::Align => None, NodeKind::Ident(_) => match parent.kind() { NodeKind::Markup { .. } => Some(Category::Interpolated), NodeKind::Math => Some(Category::Interpolated), NodeKind::FuncCall => Some(Category::Function), NodeKind::MethodCall if i > 0 => Some(Category::Function), - NodeKind::ClosureExpr if i == 0 => Some(Category::Function), - NodeKind::SetExpr => Some(Category::Function), - NodeKind::ShowExpr + NodeKind::Closure if i == 0 => Some(Category::Function), + NodeKind::SetRule => Some(Category::Function), + NodeKind::ShowRule if parent .children() .rev() @@ -336,34 +332,34 @@ impl Category { NodeKind::Str(_) => Some(Category::String), NodeKind::CodeBlock => None, NodeKind::ContentBlock => None, - NodeKind::GroupExpr => None, - NodeKind::ArrayExpr => None, - NodeKind::DictExpr => None, + NodeKind::Parenthesized => None, + NodeKind::Array => None, + NodeKind::Dict => None, NodeKind::Named => None, NodeKind::Keyed => None, - NodeKind::UnaryExpr => None, - NodeKind::BinaryExpr => None, + NodeKind::Unary => None, + NodeKind::Binary => None, NodeKind::FieldAccess => None, NodeKind::FuncCall => None, NodeKind::MethodCall => None, - NodeKind::CallArgs => None, + NodeKind::Args => None, NodeKind::Spread => None, - NodeKind::ClosureExpr => None, - NodeKind::ClosureParams => None, - NodeKind::LetExpr => None, - NodeKind::SetExpr => None, - NodeKind::ShowExpr => None, - NodeKind::WrapExpr => None, - NodeKind::IfExpr => None, - NodeKind::WhileExpr => None, - NodeKind::ForExpr => None, + NodeKind::Closure => None, + NodeKind::Params => None, + NodeKind::LetBinding => None, + NodeKind::SetRule => None, + NodeKind::ShowRule => None, + NodeKind::WrapRule => None, + NodeKind::Conditional => None, + NodeKind::WhileLoop => None, + NodeKind::ForLoop => None, NodeKind::ForPattern => None, - NodeKind::ImportExpr => None, + NodeKind::ModuleImport => None, NodeKind::ImportItems => None, - NodeKind::IncludeExpr => None, - NodeKind::BreakExpr => None, - NodeKind::ContinueExpr => None, - NodeKind::ReturnExpr => None, + NodeKind::ModuleInclude => None, + NodeKind::BreakStmt => None, + NodeKind::ContinueStmt => None, + NodeKind::ReturnStmt => None, NodeKind::Error(_, _) => Some(Category::Error), } @@ -376,15 +372,15 @@ impl Category { Self::Bracket => "punctuation.definition.bracket.typst", Self::Punctuation => "punctuation.typst", Self::Escape => "constant.character.escape.typst", - Self::Shortcut => "constant.character.shortcut.typst", - Self::Quote => "constant.character.quote.typst", + Self::Shorthand => "constant.character.shorthand.typst", + Self::SmartQuote => "constant.character.quote.typst", Self::Strong => "markup.bold.typst", Self::Emph => "markup.italic.typst", Self::Link => "markup.underline.link.typst", Self::Raw => "markup.raw.typst", Self::Math => "string.other.math.typst", Self::MathDelimiter => "punctuation.definition.math.typst", - Self::MathSymbol => "keyword.operator.math.typst", + Self::MathOperator => "keyword.operator.math.typst", Self::Heading => "markup.heading.typst", Self::ListItem => "markup.list.typst", Self::ListMarker => "punctuation.definition.list.typst", diff --git a/src/syntax/kind.rs b/src/syntax/kind.rs index 77d4cd99..3273e72d 100644 --- a/src/syntax/kind.rs +++ b/src/syntax/kind.rs @@ -1,8 +1,7 @@ use std::hash::{Hash, Hasher}; use std::sync::Arc; -use super::ast::{RawNode, Unit}; -use crate::diag::ErrorPos; +use crate::geom::{AngleUnit, LengthUnit}; use crate::util::EcoString; /// All syntactical building blocks that can be part of a Typst document. @@ -11,13 +10,9 @@ use crate::util::EcoString; /// the parser. #[derive(Debug, Clone, PartialEq)] pub enum NodeKind { - /// A line comment, two slashes followed by inner contents, terminated with - /// a newline: `//<str>\n`. + /// A line comment: `// ...`. LineComment, - /// A block comment, a slash and a star followed by inner contents, - /// terminated with a star and a slash: `/*<str>*/`. - /// - /// The comment can contain nested block comments. + /// A block comment: `/* ... */`. BlockComment, /// One or more whitespace characters. Single spaces are collapsed into text /// nodes if they would otherwise be surrounded by text nodes. @@ -43,7 +38,7 @@ pub enum NodeKind { Comma, /// A semicolon terminating an expression: `;`. Semicolon, - /// A colon between name / key and value in a dictionary, argument or + /// A colon between name/key and value in a dictionary, argument or /// parameter list, or between the term and body of a description list /// term: `:`. Colon, @@ -52,22 +47,8 @@ pub enum NodeKind { Star, /// Toggles emphasized text and indicates a subscript in a formula: `_`. Underscore, - /// Starts and ends a math formula. + /// Starts and ends a math formula: `$`. Dollar, - /// A forced line break: `\`. - Backslash, - /// The non-breaking space: `~`. - Tilde, - /// The soft hyphen: `-?`. - HyphQuest, - /// The en-dash: `--`. - Hyph2, - /// The em-dash: `---`. - Hyph3, - /// The ellipsis: `...`. - Dot3, - /// A smart quote: `'` or `"`. - Quote { double: bool }, /// The unary plus, binary addition operator, and start of enum items: `+`. Plus, /// The unary negation, binary subtraction operator, and start of list @@ -160,18 +141,37 @@ pub enum NodeKind { Markup { min_indent: usize }, /// Consecutive text without markup. Text(EcoString), - /// A unicode escape sequence, written as a slash and the letter "u" - /// followed by a hexadecimal unicode entity enclosed in curly braces: - /// `\u{1F5FA}`. + /// A forced line break: `\`. + Linebreak, + /// An escape sequence: `\#`, `\u{1F5FA}`. Escape(char), - /// Strong content: `*Strong*`. + /// A shorthand for a unicode codepoint. For example, `~` for non-breaking + /// space or `-?` for a soft hyphen. + Shorthand(char), + /// A smart quote: `'` or `"`. + SmartQuote { double: bool }, + /// Strong markup: `*Strong*`. Strong, - /// Emphasized content: `_Emphasized_`. + /// Emphasized markup: `_Emphasized_`. Emph, + /// A raw block with optional syntax highlighting: `` `...` ``. + Raw(Arc<RawKind>), /// A hyperlink: `https://typst.org`. Link(EcoString), - /// A raw block with optional syntax highlighting: `` `...` ``. - Raw(Arc<RawNode>), + /// A label: `<label>`. + Label(EcoString), + /// A reference: `@target`. + Ref(EcoString), + /// A section heading: `= Introduction`. + Heading, + /// An item of an unordered list: `- ...`. + ListItem, + /// An item of an enumeration (ordered list): `+ ...` or `1. ...`. + EnumItem, + /// An explicit enumeration numbering: `23.`. + EnumNumbering(usize), + /// An item of a description list: `/ Term: Details. + DescItem, /// A math formula: `$x$`, `$ x^2 $`. Math, /// An atom in a math formula: `x`, `+`, `12`. @@ -182,20 +182,6 @@ pub enum NodeKind { Frac, /// An alignment indicator in a math formula: `&`, `&&`. Align, - /// A section heading: `= Introduction`. - Heading, - /// An item in an unordered list: `- ...`. - ListItem, - /// An item in an enumeration (ordered list): `+ ...` or `1. ...`. - EnumItem, - /// An explicit enumeration numbering: `23.`. - EnumNumbering(usize), - /// An item in a description list: `/ Term: Details. - DescItem, - /// A label: `<label>`. - Label(EcoString), - /// A reference: `@label`. - Ref(EcoString), /// An identifier: `center`. Ident(EcoString), @@ -214,19 +200,19 @@ pub enum NodeKind { /// A content block: `[*Hi* there!]`. ContentBlock, /// A grouped expression: `(1 + 2)`. - GroupExpr, - /// An array expression: `(1, "hi", 12cm)`. - ArrayExpr, - /// A dictionary expression: `(thickness: 3pt, pattern: dashed)`. - DictExpr, + Parenthesized, + /// An array: `(1, "hi", 12cm)`. + Array, + /// A dictionary: `(thickness: 3pt, pattern: dashed)`. + Dict, /// A named pair: `thickness: 3pt`. Named, /// A keyed pair: `"spacy key": true`. Keyed, /// A unary operation: `-x`. - UnaryExpr, + Unary, /// A binary operation: `a + b`. - BinaryExpr, + Binary, /// A field access: `properties.age`. FieldAccess, /// An invocation of a function: `f(x, y)`. @@ -234,50 +220,89 @@ pub enum NodeKind { /// An invocation of a method: `array.push(v)`. MethodCall, /// A function call's argument list: `(x, y)`. - CallArgs, + Args, /// Spreaded arguments or a argument sink: `..x`. Spread, - /// A closure expression: `(x, y) => z`. - ClosureExpr, + /// A closure: `(x, y) => z`. + Closure, /// A closure's parameters: `(x, y)`. - ClosureParams, - /// A let expression: `let x = 1`. - LetExpr, - /// A set expression: `set text(...)`. - SetExpr, - /// A show expression: `show node: heading as [*{nody.body}*]`. - ShowExpr, - /// A wrap expression: `wrap body in columns(2, body)`. - WrapExpr, - /// An if-else expression: `if x { y } else { z }`. - IfExpr, - /// A while loop expression: `while x { ... }`. - WhileExpr, - /// A for loop expression: `for x in y { ... }`. - ForExpr, + Params, + /// A let binding: `let x = 1`. + LetBinding, + /// A set rule: `set text(...)`. + SetRule, + /// A show rule: `show node: heading as [*{nody.body}*]`. + ShowRule, + /// A wrap rule: `wrap body in columns(2, body)`. + WrapRule, + /// An if-else conditional: `if x { y } else { z }`. + Conditional, + /// A while loop: `while x { ... }`. + WhileLoop, + /// A for loop: `for x in y { ... }`. + ForLoop, /// A for loop's destructuring pattern: `x` or `x, y`. ForPattern, - /// An import expression: `import a, b, c from "utils.typ"`. - ImportExpr, - /// Items to import: `a, b, c`. + /// A module import: `import a, b, c from "utils.typ"`. + ModuleImport, + /// Items to import from a module: `a, b, c`. ImportItems, - /// An include expression: `include "chapter1.typ"`. - IncludeExpr, - /// A break expression: `break`. - BreakExpr, - /// A continue expression: `continue`. - ContinueExpr, - /// A return expression: `return x + 1`. - ReturnExpr, + /// A module include: `include "chapter1.typ"`. + ModuleInclude, + /// A break statement: `break`. + BreakStmt, + /// A continue statement: `continue`. + ContinueStmt, + /// A return statement: `return x + 1`. + ReturnStmt, /// An invalid sequence of characters. Error(ErrorPos, EcoString), } +/// Fields of the node kind `Raw`. +#[derive(Debug, Clone, PartialEq, Hash)] +pub struct RawKind { + /// An optional identifier specifying the language to syntax-highlight in. + pub lang: Option<EcoString>, + /// The raw text, determined as the raw string between the backticks trimmed + /// according to the above rules. + pub text: EcoString, + /// Whether the element is block-level, that is, it has 3+ backticks + /// and contains at least one newline. + pub block: bool, +} + +/// Unit of a numeric value. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum Unit { + /// An absolute length unit. + Length(LengthUnit), + /// An angular unit. + Angle(AngleUnit), + /// Font-relative: `1em` is the same as the font size. + Em, + /// Fractions: `fr`. + Fr, + /// Percentage: `%`. + Percent, +} + +/// Where in a node an error should be annotated, +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum ErrorPos { + /// Over the full width of the node. + Full, + /// At the start of the node. + Start, + /// At the end of the node. + End, +} + impl NodeKind { - /// Whether this is a kind of parenthesis. - pub fn is_paren(&self) -> bool { - matches!(self, Self::LeftParen | Self::RightParen) + /// Whether this is trivia. + pub fn is_trivia(&self) -> bool { + self.is_space() || matches!(self, Self::LineComment | Self::BlockComment) } /// Whether this is a space. @@ -285,12 +310,12 @@ impl NodeKind { matches!(self, Self::Space { .. }) } - /// Whether this is trivia. - pub fn is_trivia(&self) -> bool { - self.is_space() || matches!(self, Self::LineComment | Self::BlockComment) + /// Whether this is a left or right parenthesis. + pub fn is_paren(&self) -> bool { + matches!(self, Self::LeftParen | Self::RightParen) } - /// Whether this is a kind of error. + /// Whether this is an error. pub fn is_error(&self) -> bool { matches!(self, NodeKind::Error(_, _)) } @@ -313,14 +338,8 @@ impl NodeKind { Self::Star => "star", Self::Underscore => "underscore", Self::Dollar => "dollar sign", - Self::Backslash => "linebreak", - Self::Tilde => "non-breaking space", - Self::HyphQuest => "soft hyphen", - Self::Hyph2 => "en dash", - Self::Hyph3 => "em dash", - Self::Dot3 => "ellipsis", - Self::Quote { double: false } => "single quote", - Self::Quote { double: true } => "double quote", + Self::SmartQuote { double: false } => "single quote", + Self::SmartQuote { double: true } => "double quote", Self::Plus => "plus", Self::Minus => "minus", Self::Slash => "slash", @@ -363,23 +382,25 @@ impl NodeKind { Self::As => "keyword `as`", Self::Markup { .. } => "markup", Self::Text(_) => "text", + Self::Linebreak => "linebreak", Self::Escape(_) => "escape sequence", + Self::Shorthand(_) => "shorthand", Self::Strong => "strong content", Self::Emph => "emphasized content", - Self::Link(_) => "link", Self::Raw(_) => "raw block", - Self::Math => "math formula", - Self::Atom(_) => "math atom", - Self::Script => "script", - Self::Frac => "fraction", - Self::Align => "alignment indicator", + Self::Link(_) => "link", + Self::Label(_) => "label", + Self::Ref(_) => "reference", Self::Heading => "heading", Self::ListItem => "list item", Self::EnumItem => "enumeration item", Self::EnumNumbering(_) => "enumeration item numbering", Self::DescItem => "description list item", - Self::Label(_) => "label", - Self::Ref(_) => "reference", + Self::Math => "math formula", + Self::Atom(_) => "math atom", + Self::Script => "script", + Self::Frac => "fraction", + Self::Align => "alignment indicator", Self::Ident(_) => "identifier", Self::Bool(_) => "boolean", Self::Int(_) => "integer", @@ -388,34 +409,34 @@ impl NodeKind { Self::Str(_) => "string", Self::CodeBlock => "code block", Self::ContentBlock => "content block", - Self::GroupExpr => "group", - Self::ArrayExpr => "array", - Self::DictExpr => "dictionary", + Self::Parenthesized => "group", + Self::Array => "array", + Self::Dict => "dictionary", Self::Named => "named pair", Self::Keyed => "keyed pair", - Self::UnaryExpr => "unary expression", - Self::BinaryExpr => "binary expression", + Self::Unary => "unary expression", + Self::Binary => "binary expression", Self::FieldAccess => "field access", Self::FuncCall => "function call", Self::MethodCall => "method call", - Self::CallArgs => "call arguments", + Self::Args => "call arguments", Self::Spread => "spread", - Self::ClosureExpr => "closure", - Self::ClosureParams => "closure parameters", - Self::LetExpr => "`let` expression", - Self::SetExpr => "`set` expression", - Self::ShowExpr => "`show` expression", - Self::WrapExpr => "`wrap` expression", - Self::IfExpr => "`if` expression", - Self::WhileExpr => "while-loop expression", - Self::ForExpr => "for-loop expression", + Self::Closure => "closure", + Self::Params => "closure parameters", + Self::LetBinding => "`let` expression", + Self::SetRule => "`set` expression", + Self::ShowRule => "`show` expression", + Self::WrapRule => "`wrap` expression", + Self::Conditional => "`if` expression", + Self::WhileLoop => "while-loop expression", + Self::ForLoop => "for-loop expression", Self::ForPattern => "for-loop destructuring pattern", - Self::ImportExpr => "`import` expression", + Self::ModuleImport => "`import` expression", Self::ImportItems => "import items", - Self::IncludeExpr => "`include` expression", - Self::BreakExpr => "`break` expression", - Self::ContinueExpr => "`continue` expression", - Self::ReturnExpr => "`return` expression", + Self::ModuleInclude => "`include` expression", + Self::BreakStmt => "`break` expression", + Self::ContinueStmt => "`continue` expression", + Self::ReturnStmt => "`return` expression", Self::Error(_, _) => "syntax error", } } @@ -440,13 +461,6 @@ impl Hash for NodeKind { Self::Star => {} Self::Underscore => {} Self::Dollar => {} - Self::Backslash => {} - Self::Tilde => {} - Self::HyphQuest => {} - Self::Hyph2 => {} - Self::Hyph3 => {} - Self::Dot3 => {} - Self::Quote { double } => double.hash(state), Self::Plus => {} Self::Minus => {} Self::Slash => {} @@ -489,23 +503,26 @@ impl Hash for NodeKind { Self::As => {} Self::Markup { min_indent } => min_indent.hash(state), Self::Text(s) => s.hash(state), + Self::Linebreak => {} Self::Escape(c) => c.hash(state), + Self::Shorthand(c) => c.hash(state), + Self::SmartQuote { double } => double.hash(state), Self::Strong => {} Self::Emph => {} - Self::Link(link) => link.hash(state), Self::Raw(raw) => raw.hash(state), - Self::Math => {} - Self::Atom(c) => c.hash(state), - Self::Script => {} - Self::Frac => {} - Self::Align => {} + Self::Link(link) => link.hash(state), + Self::Label(c) => c.hash(state), + Self::Ref(c) => c.hash(state), Self::Heading => {} Self::ListItem => {} Self::EnumItem => {} Self::EnumNumbering(num) => num.hash(state), Self::DescItem => {} - Self::Label(c) => c.hash(state), - Self::Ref(c) => c.hash(state), + Self::Math => {} + Self::Atom(c) => c.hash(state), + Self::Script => {} + Self::Frac => {} + Self::Align => {} Self::Ident(v) => v.hash(state), Self::Bool(v) => v.hash(state), Self::Int(v) => v.hash(state), @@ -514,34 +531,34 @@ impl Hash for NodeKind { Self::Str(v) => v.hash(state), Self::CodeBlock => {} Self::ContentBlock => {} - Self::GroupExpr => {} - Self::ArrayExpr => {} - Self::DictExpr => {} + Self::Parenthesized => {} + Self::Array => {} + Self::Dict => {} Self::Named => {} Self::Keyed => {} - Self::UnaryExpr => {} - Self::BinaryExpr => {} + Self::Unary => {} + Self::Binary => {} Self::FieldAccess => {} Self::FuncCall => {} Self::MethodCall => {} - Self::CallArgs => {} + Self::Args => {} Self::Spread => {} - Self::ClosureExpr => {} - Self::ClosureParams => {} - Self::LetExpr => {} - Self::SetExpr => {} - Self::ShowExpr => {} - Self::WrapExpr => {} - Self::IfExpr => {} - Self::WhileExpr => {} - Self::ForExpr => {} + Self::Closure => {} + Self::Params => {} + Self::LetBinding => {} + Self::SetRule => {} + Self::ShowRule => {} + Self::WrapRule => {} + Self::Conditional => {} + Self::WhileLoop => {} + Self::ForLoop => {} Self::ForPattern => {} - Self::ImportExpr => {} + Self::ModuleImport => {} Self::ImportItems => {} - Self::IncludeExpr => {} - Self::BreakExpr => {} - Self::ContinueExpr => {} - Self::ReturnExpr => {} + Self::ModuleInclude => {} + Self::BreakStmt => {} + Self::ContinueStmt => {} + Self::ReturnStmt => {} Self::Error(pos, msg) => (pos, msg).hash(state), } } |
