summaryrefslogtreecommitdiff
path: root/src/syntax
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-10-17 16:47:07 +0200
committerLaurenz <laurmaedje@gmail.com>2022-10-17 17:11:01 +0200
commit4fd031a256b2ecfe524859d5599fafb386395572 (patch)
tree14787137b5188666a2133525d10ac0b72357551c /src/syntax
parent54b38c479060ac06213cb311f22b84bccdf88932 (diff)
More spans in AST
Diffstat (limited to 'src/syntax')
-rw-r--r--src/syntax/ast.rs823
-rw-r--r--src/syntax/highlight.rs114
-rw-r--r--src/syntax/kind.rs335
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),
}
}