Skip to main content

typst_syntax/
ast.rs

1/*!
2# Abstract Syntax Tree Interface
3
4Typst's Abstract Syntax Tree (AST) is a lazy, typed view over the untyped
5Concrete Syntax Tree (CST) and is rooted in the [`Markup`] node.
6
7## The AST is a View
8
9Most AST nodes are wrapper structs around [`SyntaxNode`] pointers. This summary
10will use a running example of the [`Raw`] node type, which is declared (after
11macro expansion) as: `struct Raw<'a>(&'a SyntaxNode);`.
12
13[`SyntaxNode`]s are generated by the parser and constitute the Concrete Syntax
14Tree (CST). The CST is _concrete_ because it has the property that an in-order
15tree traversal will recreate the text of the source file exactly.
16
17[`SyntaxNode`]s in the CST contain their [`SyntaxKind`], but don't themselves
18provide access to the semantic meaning of their contents. That semantic meaning
19is available through the Abstract Syntax Tree by iterating over CST nodes and
20inspecting their contents. The format is prepared ahead-of-time by the parser so
21that this module can unpack the abstract meaning from the CST's structure.
22
23Raw nodes are parsed by recognizing paired backtick delimiters, which you will
24find as CST nodes with the [`RawDelim`] kind. However, the AST doesn't include
25these delimiters because it _abstracts_ over the backticks. Instead, the parent
26raw node will only use its child [`RawDelim`] CST nodes to determine whether the
27element is a block or inline.
28
29## The AST is Typed
30
31AST nodes all implement the [`AstNode`] trait, but nodes can also implement
32their own unique methods. These unique methods are the "real" interface of the
33AST, and provide access to the abstract, semantic, representation of each kind
34of node. For example, the [`Raw`] node provides 3 methods that specify its
35abstract representation: [`Raw::lines()`] returns the raw text as an iterator of
36lines, [`Raw::lang()`] provides the optionally present [`RawLang`] language tag,
37and [`Raw::block()`] gives a bool for whether the raw element is a block or
38inline.
39
40This semantic information is unavailable in the CST. Only by converting a CST
41node to an AST struct will Rust let you call a method of that struct. This is a
42safe interface because the only way to create an AST node outside this file is
43to call  [`AstNode::from_untyped`]. The `node!` macro implements `from_untyped`
44by checking the node's kind before constructing it, returning `Some()` only if
45the kind matches. So we know that it will have the expected children underneath,
46otherwise the parser wouldn't have produced this node.
47
48## The AST is rooted in the [`Markup`] node
49
50The AST is rooted in the [`Markup`] node, which provides only one method:
51[`Markup::exprs`]. This returns an iterator of the main [`Expr`] enum. [`Expr`]
52is important because it contains the majority of expressions that Typst will
53evaluate. Not just markup, but also math and code expressions. Not all
54expression types are available from the parser at every step, but this does
55decrease the amount of wrapper enums needed in the AST (and this file is long
56enough already).
57
58Expressions also branch off into the remaining tree. You can view enums in this
59file as edges on a graph: areas where the tree has paths from one type to
60another (accessed through methods), then structs are the nodes of the graph,
61providing methods that return enums, etc. etc.
62
63## The AST is Lazy
64
65Being lazy means that the untyped CST nodes are converted to typed AST nodes
66only as the tree is traversed. If we parse a file and a raw block is contained
67in a branch of an if-statement that we don't take, then we won't pay the cost of
68creating an iterator over the lines or checking whether it was a block or
69inline (although it will still be parsed into nodes).
70
71This is also a factor of the current "tree-interpreter" evaluation model. A
72bytecode interpreter might instead eagerly convert the AST into bytecode, but it
73would still traverse using this lazy interface. While the tree-interpreter
74evaluation is straightforward and easy to add new features onto, it has to
75re-traverse the AST every time a function is evaluated. A bytecode interpreter
76using the lazy interface would only need to traverse each node once, improving
77throughput at the cost of initial latency and development flexibility.
78*/
79
80// The AST should never panic when traversing a CST, even if the CST is in an
81// invalid structure, e.g. if we have a syntax error or make an incorrect edit
82// from the `typst-ide` crate. We disallow common panics in this file using
83// these lints, and we provide an alternative to panicking with the
84// `AstNode::placeholder()` method.
85#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unreachable)]
86
87use std::num::NonZeroUsize;
88use std::ops::Deref;
89use std::path::Path;
90use std::str::FromStr;
91
92use ecow::EcoString;
93use typst_utils::NonZeroExt;
94use unscanny::Scanner;
95
96use crate::package::PackageSpec;
97use crate::{Span, SyntaxKind, SyntaxNode, is_ident, is_newline};
98
99/// A typed AST node.
100pub trait AstNode<'a>: Sized {
101    /// Convert a node into its typed variant.
102    fn from_untyped(node: &'a SyntaxNode) -> Option<Self>;
103
104    /// A reference to the underlying syntax node.
105    fn to_untyped(self) -> &'a SyntaxNode;
106
107    /// The source code location.
108    fn span(self) -> Span {
109        self.to_untyped().span()
110    }
111
112    /// A placeholder for this node type. If the underlying CST has syntax
113    /// errors or did not come from the parser, the AST is not guaranteed to be
114    /// valid. But instead of panicking in that case, we return placeholder
115    /// nodes.
116    fn placeholder() -> Self;
117}
118
119// A generic interface for converting untyped nodes into typed AST nodes.
120impl SyntaxNode {
121    /// Whether the node can be cast to the given AST node.
122    pub fn is<'a, T: AstNode<'a>>(&'a self) -> bool {
123        self.cast::<T>().is_some()
124    }
125
126    /// Try to convert the node to a typed AST node.
127    pub fn cast<'a, T: AstNode<'a>>(&'a self) -> Option<T> {
128        T::from_untyped(self)
129    }
130
131    /// Find the first child that can cast to the AST type `T`.
132    fn try_cast_first<'a, T: AstNode<'a>>(&'a self) -> Option<T> {
133        self.children().find_map(Self::cast)
134    }
135
136    /// Find the last child that can cast to the AST type `T`.
137    fn try_cast_last<'a, T: AstNode<'a>>(&'a self) -> Option<T> {
138        self.children().rev().find_map(Self::cast)
139    }
140
141    /// Get the first child of AST type `T` or a placeholder if none.
142    fn cast_first<'a, T: AstNode<'a>>(&'a self) -> T {
143        self.try_cast_first().unwrap_or_else(T::placeholder)
144    }
145
146    /// Get the last child of AST type `T` or a placeholder if none.
147    fn cast_last<'a, T: AstNode<'a>>(&'a self) -> T {
148        self.try_cast_last().unwrap_or_else(T::placeholder)
149    }
150}
151
152/// Implements [`AstNode`] for a struct whose name matches a [`SyntaxKind`]
153/// variant.
154///
155/// The struct becomes a wrapper around a [`SyntaxNode`] pointer, and the
156/// implementation of [`AstNode::from_untyped`] checks that the pointer's kind
157/// matches when converting, returning `Some` or `None` respectively.
158///
159/// The generated struct is the basis for typed accessor methods for properties
160/// of this AST node. For example, the [`Raw`] struct has methods for accessing
161/// its content by lines, its optional language tag, and whether the raw element
162/// is inline or a block. These methods are accessible only _after_ a
163/// `SyntaxNode` is coerced to the `Raw` struct type (via `from_untyped`),
164/// guaranteeing their implementations will work with the expected structure.
165macro_rules! node {
166    ($(#[$attr:meta])* struct $name:ident) => {
167        // Create the struct as a wrapper around a `SyntaxNode` reference.
168        #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
169        #[repr(transparent)]
170        $(#[$attr])*
171        pub struct $name<'a>(&'a SyntaxNode);
172
173        impl<'a> AstNode<'a> for $name<'a> {
174            #[inline]
175            fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
176                if node.kind() == SyntaxKind::$name {
177                    Some(Self(node))
178                } else {
179                    Option::None
180                }
181            }
182
183            #[inline]
184            fn to_untyped(self) -> &'a SyntaxNode {
185                self.0
186            }
187
188            #[inline]
189            fn placeholder() -> Self {
190                static PLACEHOLDER: SyntaxNode
191                    = SyntaxNode::placeholder(SyntaxKind::$name);
192                Self(&PLACEHOLDER)
193            }
194        }
195    };
196}
197
198node! {
199    /// A line comment: `// ...`.
200    struct LineComment
201}
202
203impl<'a> LineComment<'a> {
204    /// The contents of the line comment.
205    pub fn text(&self) -> &'a str {
206        let text = self.0.leaf_text();
207        text.strip_prefix("//").unwrap_or(text)
208    }
209}
210
211node! {
212    /// A block comment: `/* ... */`.
213    struct BlockComment
214}
215
216impl<'a> BlockComment<'a> {
217    /// The contents of the block comment.
218    pub fn text(&self) -> &'a str {
219        let text = self.0.leaf_text();
220        text.strip_prefix("/*")
221            .and_then(|text| text.strip_suffix("*/"))
222            .unwrap_or(text)
223    }
224}
225
226node! {
227    /// The syntactical root capable of representing a full parsed document.
228    struct Markup
229}
230
231impl<'a> Markup<'a> {
232    /// The expressions.
233    pub fn exprs(self) -> impl DoubleEndedIterator<Item = Expr<'a>> {
234        let mut was_stmt = false;
235        self.0
236            .children()
237            .filter(move |node| {
238                // Ignore newline directly after statements without semicolons.
239                let kind = node.kind();
240                let keep = !was_stmt || node.kind() != SyntaxKind::Space;
241                was_stmt = kind.is_stmt();
242                keep
243            })
244            .filter_map(Expr::cast_with_space)
245    }
246}
247
248/// An expression in markup, math or code.
249#[derive(Debug, Copy, Clone, Hash)]
250pub enum Expr<'a> {
251    /// Plain text without markup.
252    Text(Text<'a>),
253    /// Whitespace in markup or math. Has at most one newline in markup, as more
254    /// indicate a paragraph break.
255    Space(Space<'a>),
256    /// A forced line break: `\`.
257    Linebreak(Linebreak<'a>),
258    /// A paragraph break, indicated by one or multiple blank lines.
259    Parbreak(Parbreak<'a>),
260    /// An escape sequence: `\#`, `\u{1F5FA}`.
261    Escape(Escape<'a>),
262    /// A shorthand for a unicode codepoint. For example, `~` for non-breaking
263    /// space or `-?` for a soft hyphen.
264    Shorthand(Shorthand<'a>),
265    /// A smart quote: `'` or `"`.
266    SmartQuote(SmartQuote<'a>),
267    /// Strong content: `*Strong*`.
268    Strong(Strong<'a>),
269    /// Emphasized content: `_Emphasized_`.
270    Emph(Emph<'a>),
271    /// Raw text with optional syntax highlighting: `` `...` ``.
272    Raw(Raw<'a>),
273    /// A hyperlink: `https://typst.org`.
274    Link(Link<'a>),
275    /// A label: `<intro>`.
276    Label(Label<'a>),
277    /// A reference: `@target`, `@target[..]`.
278    Ref(Ref<'a>),
279    /// A section heading: `= Introduction`.
280    Heading(Heading<'a>),
281    /// An item in a bullet list: `- ...`.
282    ListItem(ListItem<'a>),
283    /// An item in an enumeration (numbered list): `+ ...` or `1. ...`.
284    EnumItem(EnumItem<'a>),
285    /// An item in a term list: `/ Term: Details`.
286    TermItem(TermItem<'a>),
287    /// A mathematical equation: `$x$`, `$ x^2 $`.
288    Equation(Equation<'a>),
289    /// The contents of a mathematical equation: `x^2 + 1`.
290    Math(Math<'a>),
291    /// A lone text fragment in math: `x`, `25`, `3.1415`, `=`, `[`.
292    MathText(MathText<'a>),
293    /// An identifier in math: `pi`.
294    MathIdent(MathIdent<'a>),
295    /// A field access in math: `arrow.r.long.double.bar`.
296    MathFieldAccess(MathFieldAccess<'a>),
297    /// A shorthand for a unicode codepoint in math: `a <= b`.
298    MathShorthand(MathShorthand<'a>),
299    /// An alignment point in math: `&`.
300    MathAlignPoint(MathAlignPoint<'a>),
301    /// A function call in math: `mat(delim: "[", a, b; ..#($c$,), d)`
302    MathCall(MathCall<'a>),
303    /// Matched delimiters in math: `[x + y]`.
304    MathDelimited(MathDelimited<'a>),
305    /// A base with optional attachments in math: `a_1^2`.
306    MathAttach(MathAttach<'a>),
307    /// Grouped primes in math: `a'''`.
308    MathPrimes(MathPrimes<'a>),
309    /// A fraction in math: `x/2`.
310    MathFrac(MathFrac<'a>),
311    /// A root in math: `√x`, `∛x` or `∜x`.
312    MathRoot(MathRoot<'a>),
313    /// An identifier: `left`.
314    Ident(Ident<'a>),
315    /// The `none` literal.
316    None(None<'a>),
317    /// The `auto` literal.
318    Auto(Auto<'a>),
319    /// A boolean: `true`, `false`.
320    Bool(Bool<'a>),
321    /// An integer: `120`.
322    Int(Int<'a>),
323    /// A floating-point number: `1.2`, `10e-4`.
324    Float(Float<'a>),
325    /// A numeric value with a unit: `12pt`, `3cm`, `2em`, `90deg`, `50%`.
326    Numeric(Numeric<'a>),
327    /// A quoted string: `"..."`.
328    Str(Str<'a>),
329    /// A code block: `{ let x = 1; x + 2 }`.
330    CodeBlock(CodeBlock<'a>),
331    /// A content block: `[*Hi* there!]`.
332    ContentBlock(ContentBlock<'a>),
333    /// A grouped expression: `(1 + 2)`.
334    Parenthesized(Parenthesized<'a>),
335    /// An array: `(1, "hi", 12cm)`.
336    Array(Array<'a>),
337    /// A dictionary: `(thickness: 3pt, dash: "solid")`.
338    Dict(Dict<'a>),
339    /// A unary operation: `-x`.
340    Unary(Unary<'a>),
341    /// A binary operation: `a + b`.
342    Binary(Binary<'a>),
343    /// A field access: `properties.age`.
344    FieldAccess(FieldAccess<'a>),
345    /// An invocation of a function or method: `f(x, y)`.
346    FuncCall(FuncCall<'a>),
347    /// A closure: `(x, y) => z`.
348    Closure(Closure<'a>),
349    /// A let binding: `let x = 1`.
350    LetBinding(LetBinding<'a>),
351    /// A destructuring assignment: `(x, y) = (1, 2)`.
352    DestructAssignment(DestructAssignment<'a>),
353    /// A set rule: `set text(...)`.
354    SetRule(SetRule<'a>),
355    /// A show rule: `show heading: it => emph(it.body)`.
356    ShowRule(ShowRule<'a>),
357    /// A contextual expression: `context text.lang`.
358    Contextual(Contextual<'a>),
359    /// An if-else conditional: `if x { y } else { z }`.
360    Conditional(Conditional<'a>),
361    /// A while loop: `while x { y }`.
362    WhileLoop(WhileLoop<'a>),
363    /// A for loop: `for x in y { z }`.
364    ForLoop(ForLoop<'a>),
365    /// A module import: `import "utils.typ": a, b, c`.
366    ModuleImport(ModuleImport<'a>),
367    /// A module include: `include "chapter1.typ"`.
368    ModuleInclude(ModuleInclude<'a>),
369    /// A break from a loop: `break`.
370    LoopBreak(LoopBreak<'a>),
371    /// A continue in a loop: `continue`.
372    LoopContinue(LoopContinue<'a>),
373    /// A return from a function: `return`, `return x + 1`.
374    FuncReturn(FuncReturn<'a>),
375}
376
377impl<'a> Expr<'a> {
378    fn cast_with_space(node: &'a SyntaxNode) -> Option<Self> {
379        match node.kind() {
380            SyntaxKind::Space => Some(Self::Space(Space(node))),
381            _ => Self::from_untyped(node),
382        }
383    }
384}
385
386impl<'a> AstNode<'a> for Expr<'a> {
387    fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
388        match node.kind() {
389            SyntaxKind::Space => Option::None, // Skipped unless using `cast_with_space`.
390            SyntaxKind::Linebreak => Some(Self::Linebreak(Linebreak(node))),
391            SyntaxKind::Parbreak => Some(Self::Parbreak(Parbreak(node))),
392            SyntaxKind::Text => Some(Self::Text(Text(node))),
393            SyntaxKind::Escape => Some(Self::Escape(Escape(node))),
394            SyntaxKind::Shorthand => Some(Self::Shorthand(Shorthand(node))),
395            SyntaxKind::SmartQuote => Some(Self::SmartQuote(SmartQuote(node))),
396            SyntaxKind::Strong => Some(Self::Strong(Strong(node))),
397            SyntaxKind::Emph => Some(Self::Emph(Emph(node))),
398            SyntaxKind::Raw => Some(Self::Raw(Raw(node))),
399            SyntaxKind::Link => Some(Self::Link(Link(node))),
400            SyntaxKind::Label => Some(Self::Label(Label(node))),
401            SyntaxKind::Ref => Some(Self::Ref(Ref(node))),
402            SyntaxKind::Heading => Some(Self::Heading(Heading(node))),
403            SyntaxKind::ListItem => Some(Self::ListItem(ListItem(node))),
404            SyntaxKind::EnumItem => Some(Self::EnumItem(EnumItem(node))),
405            SyntaxKind::TermItem => Some(Self::TermItem(TermItem(node))),
406            SyntaxKind::Equation => Some(Self::Equation(Equation(node))),
407            SyntaxKind::Math => Some(Self::Math(Math(node))),
408            SyntaxKind::MathText => Some(Self::MathText(MathText(node))),
409            SyntaxKind::MathIdent => Some(Self::MathIdent(MathIdent(node))),
410            SyntaxKind::MathFieldAccess => {
411                Some(Self::MathFieldAccess(MathFieldAccess(node)))
412            }
413            SyntaxKind::MathShorthand => Some(Self::MathShorthand(MathShorthand(node))),
414            SyntaxKind::MathAlignPoint => {
415                Some(Self::MathAlignPoint(MathAlignPoint(node)))
416            }
417            SyntaxKind::MathCall => Some(Self::MathCall(MathCall(node))),
418            SyntaxKind::MathDelimited => Some(Self::MathDelimited(MathDelimited(node))),
419            SyntaxKind::MathAttach => Some(Self::MathAttach(MathAttach(node))),
420            SyntaxKind::MathPrimes => Some(Self::MathPrimes(MathPrimes(node))),
421            SyntaxKind::MathFrac => Some(Self::MathFrac(MathFrac(node))),
422            SyntaxKind::MathRoot => Some(Self::MathRoot(MathRoot(node))),
423            SyntaxKind::Ident => Some(Self::Ident(Ident(node))),
424            SyntaxKind::None => Some(Self::None(None(node))),
425            SyntaxKind::Auto => Some(Self::Auto(Auto(node))),
426            SyntaxKind::Bool => Some(Self::Bool(Bool(node))),
427            SyntaxKind::Int => Some(Self::Int(Int(node))),
428            SyntaxKind::Float => Some(Self::Float(Float(node))),
429            SyntaxKind::Numeric => Some(Self::Numeric(Numeric(node))),
430            SyntaxKind::Str => Some(Self::Str(Str(node))),
431            SyntaxKind::CodeBlock => Some(Self::CodeBlock(CodeBlock(node))),
432            SyntaxKind::ContentBlock => Some(Self::ContentBlock(ContentBlock(node))),
433            SyntaxKind::Parenthesized => Some(Self::Parenthesized(Parenthesized(node))),
434            SyntaxKind::Array => Some(Self::Array(Array(node))),
435            SyntaxKind::Dict => Some(Self::Dict(Dict(node))),
436            SyntaxKind::Unary => Some(Self::Unary(Unary(node))),
437            SyntaxKind::Binary => Some(Self::Binary(Binary(node))),
438            SyntaxKind::FieldAccess => Some(Self::FieldAccess(FieldAccess(node))),
439            SyntaxKind::FuncCall => Some(Self::FuncCall(FuncCall(node))),
440            SyntaxKind::Closure => Some(Self::Closure(Closure(node))),
441            SyntaxKind::LetBinding => Some(Self::LetBinding(LetBinding(node))),
442            SyntaxKind::DestructAssignment => {
443                Some(Self::DestructAssignment(DestructAssignment(node)))
444            }
445            SyntaxKind::SetRule => Some(Self::SetRule(SetRule(node))),
446            SyntaxKind::ShowRule => Some(Self::ShowRule(ShowRule(node))),
447            SyntaxKind::Contextual => Some(Self::Contextual(Contextual(node))),
448            SyntaxKind::Conditional => Some(Self::Conditional(Conditional(node))),
449            SyntaxKind::WhileLoop => Some(Self::WhileLoop(WhileLoop(node))),
450            SyntaxKind::ForLoop => Some(Self::ForLoop(ForLoop(node))),
451            SyntaxKind::ModuleImport => Some(Self::ModuleImport(ModuleImport(node))),
452            SyntaxKind::ModuleInclude => Some(Self::ModuleInclude(ModuleInclude(node))),
453            SyntaxKind::LoopBreak => Some(Self::LoopBreak(LoopBreak(node))),
454            SyntaxKind::LoopContinue => Some(Self::LoopContinue(LoopContinue(node))),
455            SyntaxKind::FuncReturn => Some(Self::FuncReturn(FuncReturn(node))),
456            _ => Option::None,
457        }
458    }
459
460    fn to_untyped(self) -> &'a SyntaxNode {
461        match self {
462            Self::Text(v) => v.to_untyped(),
463            Self::Space(v) => v.to_untyped(),
464            Self::Linebreak(v) => v.to_untyped(),
465            Self::Parbreak(v) => v.to_untyped(),
466            Self::Escape(v) => v.to_untyped(),
467            Self::Shorthand(v) => v.to_untyped(),
468            Self::SmartQuote(v) => v.to_untyped(),
469            Self::Strong(v) => v.to_untyped(),
470            Self::Emph(v) => v.to_untyped(),
471            Self::Raw(v) => v.to_untyped(),
472            Self::Link(v) => v.to_untyped(),
473            Self::Label(v) => v.to_untyped(),
474            Self::Ref(v) => v.to_untyped(),
475            Self::Heading(v) => v.to_untyped(),
476            Self::ListItem(v) => v.to_untyped(),
477            Self::EnumItem(v) => v.to_untyped(),
478            Self::TermItem(v) => v.to_untyped(),
479            Self::Equation(v) => v.to_untyped(),
480            Self::Math(v) => v.to_untyped(),
481            Self::MathText(v) => v.to_untyped(),
482            Self::MathIdent(v) => v.to_untyped(),
483            Self::MathFieldAccess(v) => v.to_untyped(),
484            Self::MathShorthand(v) => v.to_untyped(),
485            Self::MathAlignPoint(v) => v.to_untyped(),
486            Self::MathCall(v) => v.to_untyped(),
487            Self::MathDelimited(v) => v.to_untyped(),
488            Self::MathAttach(v) => v.to_untyped(),
489            Self::MathPrimes(v) => v.to_untyped(),
490            Self::MathFrac(v) => v.to_untyped(),
491            Self::MathRoot(v) => v.to_untyped(),
492            Self::Ident(v) => v.to_untyped(),
493            Self::None(v) => v.to_untyped(),
494            Self::Auto(v) => v.to_untyped(),
495            Self::Bool(v) => v.to_untyped(),
496            Self::Int(v) => v.to_untyped(),
497            Self::Float(v) => v.to_untyped(),
498            Self::Numeric(v) => v.to_untyped(),
499            Self::Str(v) => v.to_untyped(),
500            Self::CodeBlock(v) => v.to_untyped(),
501            Self::ContentBlock(v) => v.to_untyped(),
502            Self::Array(v) => v.to_untyped(),
503            Self::Dict(v) => v.to_untyped(),
504            Self::Parenthesized(v) => v.to_untyped(),
505            Self::Unary(v) => v.to_untyped(),
506            Self::Binary(v) => v.to_untyped(),
507            Self::FieldAccess(v) => v.to_untyped(),
508            Self::FuncCall(v) => v.to_untyped(),
509            Self::Closure(v) => v.to_untyped(),
510            Self::LetBinding(v) => v.to_untyped(),
511            Self::DestructAssignment(v) => v.to_untyped(),
512            Self::SetRule(v) => v.to_untyped(),
513            Self::ShowRule(v) => v.to_untyped(),
514            Self::Contextual(v) => v.to_untyped(),
515            Self::Conditional(v) => v.to_untyped(),
516            Self::WhileLoop(v) => v.to_untyped(),
517            Self::ForLoop(v) => v.to_untyped(),
518            Self::ModuleImport(v) => v.to_untyped(),
519            Self::ModuleInclude(v) => v.to_untyped(),
520            Self::LoopBreak(v) => v.to_untyped(),
521            Self::LoopContinue(v) => v.to_untyped(),
522            Self::FuncReturn(v) => v.to_untyped(),
523        }
524    }
525
526    fn placeholder() -> Self {
527        Self::None(None::placeholder())
528    }
529}
530
531impl Expr<'_> {
532    /// Can this expression be embedded into markup with a hash?
533    pub fn hash(self) -> bool {
534        matches!(
535            self,
536            Self::Ident(_)
537                | Self::None(_)
538                | Self::Auto(_)
539                | Self::Bool(_)
540                | Self::Int(_)
541                | Self::Float(_)
542                | Self::Numeric(_)
543                | Self::Str(_)
544                | Self::CodeBlock(_)
545                | Self::ContentBlock(_)
546                | Self::Array(_)
547                | Self::Dict(_)
548                | Self::Parenthesized(_)
549                | Self::FieldAccess(_)
550                | Self::FuncCall(_)
551                | Self::LetBinding(_)
552                | Self::SetRule(_)
553                | Self::ShowRule(_)
554                | Self::Contextual(_)
555                | Self::Conditional(_)
556                | Self::WhileLoop(_)
557                | Self::ForLoop(_)
558                | Self::ModuleImport(_)
559                | Self::ModuleInclude(_)
560                | Self::LoopBreak(_)
561                | Self::LoopContinue(_)
562                | Self::FuncReturn(_)
563        )
564    }
565
566    /// Is this a literal?
567    pub fn is_literal(self) -> bool {
568        matches!(
569            self,
570            Self::None(_)
571                | Self::Auto(_)
572                | Self::Bool(_)
573                | Self::Int(_)
574                | Self::Float(_)
575                | Self::Numeric(_)
576                | Self::Str(_)
577        )
578    }
579}
580
581node! {
582    /// Plain text without markup.
583    struct Text
584}
585
586impl<'a> Text<'a> {
587    /// Get the text.
588    pub fn get(self) -> &'a EcoString {
589        self.0.leaf_text()
590    }
591}
592
593node! {
594    /// Whitespace in markup or math. Has at most one newline in markup, as more
595    /// indicate a paragraph break.
596    struct Space
597}
598
599node! {
600    /// A forced line break: `\`.
601    struct Linebreak
602}
603
604node! {
605    /// A paragraph break, indicated by one or multiple blank lines.
606    struct Parbreak
607}
608
609node! {
610    /// An escape sequence: `\#`, `\u{1F5FA}`.
611    struct Escape
612}
613
614impl Escape<'_> {
615    /// Get the escaped character.
616    pub fn get(self) -> char {
617        let mut s = Scanner::new(self.0.leaf_text());
618        s.expect('\\');
619        if s.eat_if("u{") {
620            let hex = s.eat_while(char::is_ascii_hexdigit);
621            u32::from_str_radix(hex, 16)
622                .ok()
623                .and_then(std::char::from_u32)
624                .unwrap_or_default()
625        } else {
626            s.eat().unwrap_or_default()
627        }
628    }
629}
630
631node! {
632    /// A shorthand for a unicode codepoint. For example, `~` for a non-breaking
633    /// space or `-?` for a soft hyphen.
634    struct Shorthand
635}
636
637impl Shorthand<'_> {
638    /// A list of all shorthands in markup mode.
639    pub const LIST: &'static [(&'static str, char)] = &[
640        ("...", '…'),
641        ("~", '\u{00A0}'),
642        ("-", '\u{2212}'), // Only before a digit
643        ("--", '\u{2013}'),
644        ("---", '\u{2014}'),
645        ("-?", '\u{00AD}'),
646    ];
647
648    /// Get the shorthanded character.
649    pub fn get(self) -> char {
650        let text = self.0.leaf_text();
651        Self::LIST
652            .iter()
653            .find(|&&(s, _)| s == text)
654            .map_or_else(char::default, |&(_, c)| c)
655    }
656}
657
658node! {
659    /// A smart quote: `'` or `"`.
660    struct SmartQuote
661}
662
663impl SmartQuote<'_> {
664    /// Whether this is a double quote.
665    pub fn double(self) -> bool {
666        self.0.leaf_text() == "\""
667    }
668}
669
670node! {
671    /// Strong content: `*Strong*`.
672    struct Strong
673}
674
675impl<'a> Strong<'a> {
676    /// The contents of the strong node.
677    pub fn body(self) -> Markup<'a> {
678        self.0.cast_first()
679    }
680}
681
682node! {
683    /// Emphasized content: `_Emphasized_`.
684    struct Emph
685}
686
687impl<'a> Emph<'a> {
688    /// The contents of the emphasis node.
689    pub fn body(self) -> Markup<'a> {
690        self.0.cast_first()
691    }
692}
693
694node! {
695    /// Raw text with optional syntax highlighting: `` `...` ``.
696    struct Raw
697}
698
699impl<'a> Raw<'a> {
700    /// The lines in the raw block.
701    pub fn lines(self) -> impl DoubleEndedIterator<Item = Text<'a>> {
702        self.0.children().filter_map(SyntaxNode::cast)
703    }
704
705    /// An optional identifier specifying the language to syntax-highlight in.
706    pub fn lang(self) -> Option<RawLang<'a>> {
707        // Only blocky literals are supposed to contain a language.
708        let delim: RawDelim = self.0.try_cast_first()?;
709        if delim.0.len() < 3 {
710            return Option::None;
711        }
712
713        self.0.try_cast_first()
714    }
715
716    /// Whether the raw text should be displayed in a separate block.
717    pub fn block(self) -> bool {
718        self.0
719            .try_cast_first()
720            .is_some_and(|delim: RawDelim| delim.0.len() >= 3)
721            && self.0.children().any(|e| {
722                e.kind() == SyntaxKind::RawTrimmed
723                    && e.leaf_text().chars().any(is_newline)
724            })
725    }
726}
727
728node! {
729    /// A language tag at the start of raw element: ``typ ``.
730    struct RawLang
731}
732
733impl<'a> RawLang<'a> {
734    /// Get the language tag.
735    pub fn get(self) -> &'a EcoString {
736        self.0.leaf_text()
737    }
738}
739
740node! {
741    /// A raw delimiter in single or 3+ backticks: `` ` ``.
742    struct RawDelim
743}
744
745node! {
746    /// A hyperlink: `https://typst.org`.
747    struct Link
748}
749
750impl<'a> Link<'a> {
751    /// Get the URL.
752    pub fn get(self) -> &'a EcoString {
753        self.0.leaf_text()
754    }
755}
756
757node! {
758    /// A label: `<intro>`.
759    struct Label
760}
761
762impl<'a> Label<'a> {
763    /// Get the label's text.
764    pub fn get(self) -> &'a str {
765        self.0.leaf_text().trim_start_matches('<').trim_end_matches('>')
766    }
767}
768
769node! {
770    /// A reference: `@target`, `@target[..]`.
771    struct Ref
772}
773
774impl<'a> Ref<'a> {
775    /// Get the target.
776    ///
777    /// Will not be empty.
778    pub fn target(self) -> &'a str {
779        self.0
780            .children()
781            .find(|node| node.kind() == SyntaxKind::RefMarker)
782            .map(|node| node.leaf_text().trim_start_matches('@'))
783            .unwrap_or_default()
784    }
785
786    /// Get the supplement.
787    pub fn supplement(self) -> Option<ContentBlock<'a>> {
788        self.0.try_cast_last()
789    }
790}
791
792node! {
793    /// A section heading: `= Introduction`.
794    struct Heading
795}
796
797impl<'a> Heading<'a> {
798    /// The contents of the heading.
799    pub fn body(self) -> Markup<'a> {
800        self.0.cast_first()
801    }
802
803    /// The section depth (number of equals signs).
804    pub fn depth(self) -> NonZeroUsize {
805        self.0
806            .children()
807            .find(|node| node.kind() == SyntaxKind::HeadingMarker)
808            .and_then(|node| node.len().try_into().ok())
809            .unwrap_or(NonZeroUsize::ONE)
810    }
811}
812
813node! {
814    /// An item in a bullet list: `- ...`.
815    struct ListItem
816}
817
818impl<'a> ListItem<'a> {
819    /// The contents of the list item.
820    pub fn body(self) -> Markup<'a> {
821        self.0.cast_first()
822    }
823}
824
825node! {
826    /// An item in an enumeration (numbered list): `+ ...` or `1. ...`.
827    struct EnumItem
828}
829
830impl<'a> EnumItem<'a> {
831    /// The explicit numbering, if any: `23.`.
832    pub fn number(self) -> Option<u64> {
833        self.0.children().find_map(|node| match node.kind() {
834            SyntaxKind::EnumMarker => node.leaf_text().trim_end_matches('.').parse().ok(),
835            _ => Option::None,
836        })
837    }
838
839    /// The contents of the list item.
840    pub fn body(self) -> Markup<'a> {
841        self.0.cast_first()
842    }
843}
844
845node! {
846    /// An item in a term list: `/ Term: Details`.
847    struct TermItem
848}
849
850impl<'a> TermItem<'a> {
851    /// The term described by the item.
852    pub fn term(self) -> Markup<'a> {
853        self.0.cast_first()
854    }
855
856    /// The description of the term.
857    pub fn description(self) -> Markup<'a> {
858        self.0.cast_last()
859    }
860}
861
862node! {
863    /// A mathematical equation: `$x$`, `$ x^2 $`.
864    struct Equation
865}
866
867impl<'a> Equation<'a> {
868    /// The contained math.
869    pub fn body(self) -> Math<'a> {
870        self.0.cast_first()
871    }
872
873    /// Whether the equation should be displayed as a separate block.
874    pub fn block(self) -> bool {
875        let is_space = |node: Option<&SyntaxNode>| {
876            node.map(SyntaxNode::kind) == Some(SyntaxKind::Space)
877        };
878        is_space(self.0.children().nth(1)) && is_space(self.0.children().nth_back(1))
879    }
880}
881
882node! {
883    /// The contents of a mathematical equation: `x^2 + 1`.
884    struct Math
885}
886
887impl<'a> Math<'a> {
888    /// The expressions the mathematical content consists of.
889    pub fn exprs(self) -> impl DoubleEndedIterator<Item = Expr<'a>> {
890        self.0.children().filter_map(Expr::cast_with_space)
891    }
892
893    /// Whether this `Math` node was originally parenthesized.
894    pub fn was_deparenthesized(self) -> bool {
895        let mut iter = self.0.children();
896        matches!(iter.next().map(SyntaxNode::kind), Some(SyntaxKind::LeftParen))
897            && matches!(
898                iter.next_back().map(SyntaxNode::kind),
899                Some(SyntaxKind::RightParen)
900            )
901    }
902}
903
904node! {
905    /// A lone text fragment in math: `x`, `25`, `3.1415`, `=`, `[`.
906    struct MathText
907}
908
909/// The underlying text kind.
910pub enum MathTextKind<'a> {
911    Grapheme(&'a EcoString),
912    Number(&'a EcoString),
913}
914
915impl<'a> MathText<'a> {
916    /// Return the underlying text.
917    pub fn get(self) -> MathTextKind<'a> {
918        let text = self.0.leaf_text();
919        if text.chars().next().unwrap_or_default().is_numeric() {
920            // Numbers are potentially grouped as multiple characters. This is
921            // done in `Lexer::math_text()`.
922            MathTextKind::Number(text)
923        } else {
924            MathTextKind::Grapheme(text)
925        }
926    }
927}
928
929node! {
930    /// An identifier in math: `pi`.
931    struct MathIdent
932}
933
934impl<'a> MathIdent<'a> {
935    /// Get the identifier.
936    pub fn get(self) -> &'a EcoString {
937        self.0.leaf_text()
938    }
939
940    /// Get the identifier as a string slice.
941    pub fn as_str(self) -> &'a str {
942        self.get()
943    }
944}
945
946impl Deref for MathIdent<'_> {
947    type Target = str;
948
949    /// Dereference to a string. Note that this shortens the lifetime, so you
950    /// may need to use [`get()`](Self::get) instead in some situations.
951    fn deref(&self) -> &Self::Target {
952        self.as_str()
953    }
954}
955
956node! {
957    /// A field access in math: `arrow.r.long.double.bar`.
958    struct MathFieldAccess
959}
960
961impl<'a> MathFieldAccess<'a> {
962    /// The expression to access the field on.
963    pub fn target(self) -> MathAccess<'a> {
964        self.0.cast_first()
965    }
966
967    /// The name of the field.
968    pub fn field(self) -> MathIdent<'a> {
969        self.0.cast_last()
970    }
971}
972
973/// A variable or field access in math.
974#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
975pub enum MathAccess<'a> {
976    MathIdent(MathIdent<'a>),
977    MathFieldAccess(MathFieldAccess<'a>),
978}
979
980impl<'a> AstNode<'a> for MathAccess<'a> {
981    fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
982        match node.kind() {
983            SyntaxKind::MathIdent => Some(Self::MathIdent(MathIdent(node))),
984            SyntaxKind::MathFieldAccess => {
985                Some(Self::MathFieldAccess(MathFieldAccess(node)))
986            }
987            _ => Option::None,
988        }
989    }
990
991    fn to_untyped(self) -> &'a SyntaxNode {
992        match self {
993            Self::MathIdent(v) => v.to_untyped(),
994            Self::MathFieldAccess(v) => v.to_untyped(),
995        }
996    }
997
998    fn placeholder() -> Self {
999        Self::MathIdent(MathIdent::placeholder())
1000    }
1001}
1002
1003node! {
1004    /// A shorthand for a unicode codepoint in math: `a <= b`.
1005    struct MathShorthand
1006}
1007
1008impl MathShorthand<'_> {
1009    /// A list of all shorthands in math mode.
1010    pub const LIST: &'static [(&'static str, char)] = &[
1011        ("...", '…'),
1012        ("-", '−'),
1013        ("*", '∗'),
1014        ("~", '∼'),
1015        ("!=", '≠'),
1016        (":=", '≔'),
1017        ("::=", '⩴'),
1018        ("=:", '≕'),
1019        ("<<", '≪'),
1020        ("<<<", '⋘'),
1021        (">>", '≫'),
1022        (">>>", '⋙'),
1023        ("<=", '≤'),
1024        (">=", '≥'),
1025        ("->", '→'),
1026        ("-->", '⟶'),
1027        ("|->", '↦'),
1028        (">->", '↣'),
1029        ("->>", '↠'),
1030        ("<-", '←'),
1031        ("<--", '⟵'),
1032        ("<-<", '↢'),
1033        ("<<-", '↞'),
1034        ("<->", '↔'),
1035        ("<-->", '⟷'),
1036        ("~>", '⇝'),
1037        ("~~>", '⟿'),
1038        ("<~", '⇜'),
1039        ("<~~", '⬳'),
1040        ("=>", '⇒'),
1041        ("|=>", '⤇'),
1042        ("==>", '⟹'),
1043        ("<==", '⟸'),
1044        ("<=>", '⇔'),
1045        ("<==>", '⟺'),
1046        ("[|", '⟦'),
1047        ("|]", '⟧'),
1048        ("||", '‖'),
1049    ];
1050
1051    /// Get the shorthanded character.
1052    pub fn get(self) -> char {
1053        let text = self.0.leaf_text();
1054        Self::LIST
1055            .iter()
1056            .find(|&&(s, _)| s == text)
1057            .map_or_else(char::default, |&(_, c)| c)
1058    }
1059}
1060
1061node! {
1062    /// A function call in math: `mat(delim: "[", a, b; ..#($c$,), d)`.
1063    struct MathCall
1064}
1065
1066impl<'a> MathCall<'a> {
1067    /// The function to call. If not actually a function, will be rendered as
1068    /// content next to its arguments.
1069    pub fn callee(self) -> MathAccess<'a> {
1070        self.0.cast_first()
1071    }
1072
1073    /// The arguments to the function.
1074    pub fn args(self) -> MathArgs<'a> {
1075        self.0.cast_last()
1076    }
1077}
1078
1079node! {
1080    /// Function arguments in math: `(delim: "[", a, b; ..#($c$,), d)`.
1081    struct MathArgs
1082}
1083
1084/// An argument in a [`MathCall`] for an actual function and whether it ends in
1085/// a semicolon.
1086#[derive(Debug, Copy, Clone, Hash)]
1087pub struct MathArg<'a> {
1088    /// The argument.
1089    pub arg: Arg<'a>,
1090    /// Whether the argument ends with a semicolon and should create
1091    /// two-dimensional args. This excludes semicolons that end embedded code
1092    /// expressions.
1093    pub ends_in_semicolon: bool,
1094}
1095
1096/// Items at the top-level of a [`MathCall`] argument list that will be rendered
1097/// into content if unparsing for a non-function.
1098///
1099/// This enum does not implement [`AstNode`] because the `Semicolon` variant
1100/// requires extra context to convert correctly making it a likely footgun.
1101#[derive(Debug, Copy, Clone, Hash)]
1102pub enum MathArgItem<'a> {
1103    /// A normal argument.
1104    Arg(Arg<'a>),
1105    /// A space between arguments and other punctuation.
1106    Space(Space<'a>),
1107    /// A comma separating arguments.
1108    Comma(char, &'a SyntaxNode),
1109    /// A semicolon separating arguments. This excludes semicolons that end
1110    /// embedded code expressions.
1111    Semicolon(char, &'a SyntaxNode),
1112    /// The left paren at the start of the arguments.
1113    LeftParen(char, &'a SyntaxNode),
1114    /// The right paren at the end of the arguments.
1115    RightParen(char, &'a SyntaxNode),
1116}
1117
1118impl<'a> MathArgs<'a> {
1119    /// Arguments for actual function calls in math.
1120    pub fn arg_items(self) -> impl Iterator<Item = MathArg<'a>> {
1121        let mut content_items = self.content_items().peekable();
1122        std::iter::from_fn(move || {
1123            let arg = content_items.find_map(|node| match node {
1124                MathArgItem::Arg(arg) => Some(arg),
1125                _ => Option::None,
1126            })?;
1127
1128            // `self.content_items()` handles code-ending semicolons for us :)
1129            let ends_in_semicolon = loop {
1130                match content_items.peek() {
1131                    Option::None | Some(MathArgItem::Arg(_)) => break false,
1132                    Some(MathArgItem::Semicolon(_, _)) => break true,
1133                    Some(_) => {}
1134                }
1135                content_items.next();
1136            };
1137
1138            Some(MathArg { arg, ends_in_semicolon })
1139        })
1140    }
1141
1142    /// Items at the top-level of the argument list that will be rendered into
1143    /// content if unparsing for a non-function.
1144    pub fn content_items(self) -> impl Iterator<Item = MathArgItem<'a>> {
1145        let mut children = self.0.children().peekable();
1146        let mut prev_hash = false;
1147        std::iter::from_fn(move || {
1148            for node in children.by_ref() {
1149                if let Some(arg) = node.cast() {
1150                    return Some(MathArgItem::Arg(arg));
1151                }
1152                let semicolon_ends_code = prev_hash;
1153                prev_hash = false;
1154                let item = match node.kind() {
1155                    SyntaxKind::Space => MathArgItem::Space(Space(node)),
1156                    SyntaxKind::Comma => MathArgItem::Comma(',', node),
1157                    SyntaxKind::LeftParen => MathArgItem::LeftParen('(', node),
1158                    SyntaxKind::RightParen => MathArgItem::RightParen(')', node),
1159                    SyntaxKind::Semicolon if !semicolon_ends_code => {
1160                        MathArgItem::Semicolon(';', node)
1161                    }
1162                    SyntaxKind::Hash => {
1163                        prev_hash = true;
1164                        continue;
1165                    }
1166                    _ => continue,
1167                };
1168                return Some(item);
1169            }
1170            Option::None
1171        })
1172    }
1173}
1174
1175node! {
1176    /// An alignment point in math: `&`.
1177    struct MathAlignPoint
1178}
1179
1180node! {
1181    /// Matched delimiters in math: `[x + y]`.
1182    struct MathDelimited
1183}
1184
1185impl<'a> MathDelimited<'a> {
1186    /// The opening delimiter.
1187    pub fn open(self) -> Expr<'a> {
1188        self.0.cast_first()
1189    }
1190
1191    /// The contents, including the delimiters.
1192    pub fn body(self) -> Math<'a> {
1193        self.0.cast_first()
1194    }
1195
1196    /// The closing delimiter.
1197    pub fn close(self) -> Expr<'a> {
1198        self.0.cast_last()
1199    }
1200}
1201
1202node! {
1203    /// A base with optional attachments in math: `a_1^2`.
1204    struct MathAttach
1205}
1206
1207impl<'a> MathAttach<'a> {
1208    /// The base, to which things are attached.
1209    pub fn base(self) -> Expr<'a> {
1210        self.0.cast_first()
1211    }
1212
1213    /// The bottom attachment.
1214    pub fn bottom(self) -> Option<Expr<'a>> {
1215        self.0
1216            .children()
1217            .skip_while(|node| !matches!(node.kind(), SyntaxKind::Underscore))
1218            .find_map(SyntaxNode::cast)
1219    }
1220
1221    /// The top attachment.
1222    pub fn top(self) -> Option<Expr<'a>> {
1223        self.0
1224            .children()
1225            .skip_while(|node| !matches!(node.kind(), SyntaxKind::Hat))
1226            .find_map(SyntaxNode::cast)
1227    }
1228
1229    /// Extract attached primes if present.
1230    pub fn primes(self) -> Option<MathPrimes<'a>> {
1231        self.0
1232            .children()
1233            .skip_while(|node| node.cast::<Expr<'_>>().is_none())
1234            .nth(1)
1235            .and_then(|n| n.cast())
1236    }
1237}
1238
1239node! {
1240    /// Grouped primes in math: `a'''`.
1241    struct MathPrimes
1242}
1243
1244impl MathPrimes<'_> {
1245    /// The number of grouped primes.
1246    pub fn count(self) -> usize {
1247        // We can use byte length since single quotes are one byte.
1248        self.0.leaf_text().len()
1249    }
1250}
1251
1252node! {
1253    /// A fraction in math: `x/2`
1254    struct MathFrac
1255}
1256
1257impl<'a> MathFrac<'a> {
1258    /// The numerator.
1259    pub fn num(self) -> Expr<'a> {
1260        self.0.cast_first()
1261    }
1262
1263    /// The denominator.
1264    pub fn denom(self) -> Expr<'a> {
1265        self.0.cast_last()
1266    }
1267}
1268
1269node! {
1270    /// A root in math: `√x`, `∛x` or `∜x`.
1271    struct MathRoot
1272}
1273
1274impl<'a> MathRoot<'a> {
1275    /// The index of the root.
1276    pub fn index(self) -> Option<u8> {
1277        match self.0.children().next().map(|node| node.leaf_text().as_str()) {
1278            Some("∜") => Some(4),
1279            Some("∛") => Some(3),
1280            Some("√") => Option::None,
1281            _ => Option::None,
1282        }
1283    }
1284
1285    /// The radicand.
1286    pub fn radicand(self) -> Expr<'a> {
1287        self.0.cast_first()
1288    }
1289}
1290
1291node! {
1292    /// An identifier: `it`.
1293    struct Ident
1294}
1295
1296impl<'a> Ident<'a> {
1297    /// Get the identifier.
1298    pub fn get(self) -> &'a EcoString {
1299        self.0.leaf_text()
1300    }
1301
1302    /// Get the identifier as a string slice.
1303    pub fn as_str(self) -> &'a str {
1304        self.get()
1305    }
1306}
1307
1308impl Deref for Ident<'_> {
1309    type Target = str;
1310
1311    /// Dereference to a string. Note that this shortens the lifetime, so you
1312    /// may need to use [`get()`](Self::get) instead in some situations.
1313    fn deref(&self) -> &Self::Target {
1314        self.as_str()
1315    }
1316}
1317
1318node! {
1319    /// The `none` literal.
1320    struct None
1321}
1322
1323node! {
1324    /// The `auto` literal.
1325    struct Auto
1326}
1327
1328node! {
1329    /// A boolean: `true`, `false`.
1330    struct Bool
1331}
1332
1333impl Bool<'_> {
1334    /// Get the boolean value.
1335    pub fn get(self) -> bool {
1336        self.0.leaf_text() == "true"
1337    }
1338}
1339
1340node! {
1341    /// An integer: `120`.
1342    struct Int
1343}
1344
1345impl Int<'_> {
1346    /// Get the integer value.
1347    pub fn get(self) -> i64 {
1348        let text = self.0.leaf_text();
1349        if let Some(rest) = text.strip_prefix("0x") {
1350            i64::from_str_radix(rest, 16)
1351        } else if let Some(rest) = text.strip_prefix("0o") {
1352            i64::from_str_radix(rest, 8)
1353        } else if let Some(rest) = text.strip_prefix("0b") {
1354            i64::from_str_radix(rest, 2)
1355        } else {
1356            text.parse()
1357        }
1358        .unwrap_or_default()
1359    }
1360}
1361
1362node! {
1363    /// A floating-point number: `1.2`, `10e-4`.
1364    struct Float
1365}
1366
1367impl Float<'_> {
1368    /// Get the floating-point value.
1369    pub fn get(self) -> f64 {
1370        self.0.leaf_text().parse().unwrap_or_default()
1371    }
1372}
1373
1374node! {
1375    /// A numeric value with a unit: `12pt`, `3cm`, `2em`, `90deg`, `50%`.
1376    struct Numeric
1377}
1378
1379impl Numeric<'_> {
1380    /// Get the numeric value and unit.
1381    pub fn get(self) -> (f64, Unit) {
1382        let text = self.0.leaf_text();
1383        let count = text
1384            .chars()
1385            .rev()
1386            .take_while(|c| matches!(c, 'a'..='z' | '%'))
1387            .count();
1388
1389        let split = text.len() - count;
1390        let value = text[..split].parse().unwrap_or_default();
1391        let unit = match &text[split..] {
1392            "pt" => Unit::Pt,
1393            "mm" => Unit::Mm,
1394            "cm" => Unit::Cm,
1395            "in" => Unit::In,
1396            "deg" => Unit::Deg,
1397            "rad" => Unit::Rad,
1398            "em" => Unit::Em,
1399            "fr" => Unit::Fr,
1400            "%" => Unit::Percent,
1401            _ => Unit::Percent,
1402        };
1403
1404        (value, unit)
1405    }
1406}
1407
1408/// Unit of a numeric value.
1409#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1410pub enum Unit {
1411    /// Points.
1412    Pt,
1413    /// Millimeters.
1414    Mm,
1415    /// Centimeters.
1416    Cm,
1417    /// Inches.
1418    In,
1419    /// Radians.
1420    Rad,
1421    /// Degrees.
1422    Deg,
1423    /// Font-relative: `1em` is the same as the font size.
1424    Em,
1425    /// Fractions: `fr`.
1426    Fr,
1427    /// Percentage: `%`.
1428    Percent,
1429}
1430
1431node! {
1432    /// A quoted string: `"..."`.
1433    struct Str
1434}
1435
1436impl Str<'_> {
1437    /// Get the string value with resolved escape sequences.
1438    pub fn get(self) -> EcoString {
1439        let text = self.0.leaf_text();
1440        let unquoted = &text[1..text.len() - 1];
1441        if !unquoted.contains('\\') {
1442            return unquoted.into();
1443        }
1444
1445        let mut out = EcoString::with_capacity(unquoted.len());
1446        let mut s = Scanner::new(unquoted);
1447
1448        while let Some(c) = s.eat() {
1449            if c != '\\' {
1450                out.push(c);
1451                continue;
1452            }
1453
1454            let start = s.locate(-1);
1455            match s.eat() {
1456                Some('\\') => out.push('\\'),
1457                Some('"') => out.push('"'),
1458                Some('n') => out.push('\n'),
1459                Some('r') => out.push('\r'),
1460                Some('t') => out.push('\t'),
1461                Some('u') if s.eat_if('{') => {
1462                    let sequence = s.eat_while(char::is_ascii_hexdigit);
1463                    s.eat_if('}');
1464
1465                    match u32::from_str_radix(sequence, 16)
1466                        .ok()
1467                        .and_then(std::char::from_u32)
1468                    {
1469                        Some(c) => out.push(c),
1470                        Option::None => out.push_str(s.from(start)),
1471                    }
1472                }
1473                _ => out.push_str(s.from(start)),
1474            }
1475        }
1476
1477        out
1478    }
1479}
1480
1481node! {
1482    /// A code block: `{ let x = 1; x + 2 }`.
1483    struct CodeBlock
1484}
1485
1486impl<'a> CodeBlock<'a> {
1487    /// The contained code.
1488    pub fn body(self) -> Code<'a> {
1489        self.0.cast_first()
1490    }
1491}
1492
1493node! {
1494    /// The body of a code block.
1495    struct Code
1496}
1497
1498impl<'a> Code<'a> {
1499    /// The list of expressions contained in the code.
1500    pub fn exprs(self) -> impl DoubleEndedIterator<Item = Expr<'a>> {
1501        self.0.children().filter_map(SyntaxNode::cast)
1502    }
1503}
1504
1505node! {
1506    /// A content block: `[*Hi* there!]`.
1507    struct ContentBlock
1508}
1509
1510impl<'a> ContentBlock<'a> {
1511    /// The contained markup.
1512    pub fn body(self) -> Markup<'a> {
1513        self.0.cast_first()
1514    }
1515}
1516
1517node! {
1518    /// A grouped expression: `(1 + 2)`.
1519    struct Parenthesized
1520}
1521
1522impl<'a> Parenthesized<'a> {
1523    /// The wrapped expression.
1524    ///
1525    /// Should only be accessed if this is contained in an `Expr`.
1526    pub fn expr(self) -> Expr<'a> {
1527        self.0.cast_first()
1528    }
1529
1530    /// The wrapped pattern.
1531    ///
1532    /// Should only be accessed if this is contained in a `Pattern`.
1533    pub fn pattern(self) -> Pattern<'a> {
1534        self.0.cast_first()
1535    }
1536}
1537
1538node! {
1539    /// An array: `(1, "hi", 12cm)`.
1540    struct Array
1541}
1542
1543impl<'a> Array<'a> {
1544    /// The array's items.
1545    pub fn items(self) -> impl DoubleEndedIterator<Item = ArrayItem<'a>> {
1546        self.0.children().filter_map(SyntaxNode::cast)
1547    }
1548}
1549
1550/// An item in an array.
1551#[derive(Debug, Copy, Clone, Hash)]
1552pub enum ArrayItem<'a> {
1553    /// A bare expression: `12`.
1554    Pos(Expr<'a>),
1555    /// A spread expression: `..things`.
1556    Spread(Spread<'a>),
1557}
1558
1559impl<'a> AstNode<'a> for ArrayItem<'a> {
1560    fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
1561        match node.kind() {
1562            SyntaxKind::Spread => Some(Self::Spread(Spread(node))),
1563            _ => node.cast().map(Self::Pos),
1564        }
1565    }
1566
1567    fn to_untyped(self) -> &'a SyntaxNode {
1568        match self {
1569            Self::Pos(v) => v.to_untyped(),
1570            Self::Spread(v) => v.to_untyped(),
1571        }
1572    }
1573
1574    fn placeholder() -> Self {
1575        Self::Pos(Expr::placeholder())
1576    }
1577}
1578
1579node! {
1580    /// A dictionary: `(thickness: 3pt, dash: "solid")`.
1581    struct Dict
1582}
1583
1584impl<'a> Dict<'a> {
1585    /// The dictionary's items.
1586    pub fn items(self) -> impl DoubleEndedIterator<Item = DictItem<'a>> {
1587        self.0.children().filter_map(SyntaxNode::cast)
1588    }
1589}
1590
1591/// An item in an dictionary expression.
1592#[derive(Debug, Copy, Clone, Hash)]
1593pub enum DictItem<'a> {
1594    /// A named pair: `thickness: 3pt`.
1595    Named(Named<'a>),
1596    /// A keyed pair: `"spacy key": true`.
1597    Keyed(Keyed<'a>),
1598    /// A spread expression: `..things`.
1599    Spread(Spread<'a>),
1600}
1601
1602impl<'a> AstNode<'a> for DictItem<'a> {
1603    fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
1604        match node.kind() {
1605            SyntaxKind::Named => Some(Self::Named(Named(node))),
1606            SyntaxKind::Keyed => Some(Self::Keyed(Keyed(node))),
1607            SyntaxKind::Spread => Some(Self::Spread(Spread(node))),
1608            _ => Option::None,
1609        }
1610    }
1611
1612    fn to_untyped(self) -> &'a SyntaxNode {
1613        match self {
1614            Self::Named(v) => v.to_untyped(),
1615            Self::Keyed(v) => v.to_untyped(),
1616            Self::Spread(v) => v.to_untyped(),
1617        }
1618    }
1619
1620    fn placeholder() -> Self {
1621        Self::Spread(Spread::placeholder())
1622    }
1623}
1624
1625node! {
1626    /// A named pair: `thickness: 3pt`.
1627    struct Named
1628}
1629
1630impl<'a> Named<'a> {
1631    /// The name: `thickness`.
1632    pub fn name(self) -> Ident<'a> {
1633        self.0.cast_first()
1634    }
1635
1636    /// The right-hand side of the pair: `3pt`.
1637    ///
1638    /// This should only be accessed if this `Named` is contained in a
1639    /// `DictItem`, `Arg`, or `Param`.
1640    pub fn expr(self) -> Expr<'a> {
1641        self.0.cast_last()
1642    }
1643
1644    /// The right-hand side of the pair as a pattern.
1645    ///
1646    /// This should only be accessed if this `Named` is contained in a
1647    /// `Destructuring`.
1648    pub fn pattern(self) -> Pattern<'a> {
1649        self.0.cast_last()
1650    }
1651}
1652
1653node! {
1654    /// A keyed pair: `"spacy key": true`.
1655    struct Keyed
1656}
1657
1658impl<'a> Keyed<'a> {
1659    /// The key: `"spacy key"`.
1660    pub fn key(self) -> Expr<'a> {
1661        self.0.cast_first()
1662    }
1663
1664    /// The right-hand side of the pair: `true`.
1665    ///
1666    /// This should only be accessed if this `Keyed` is contained in a
1667    /// `DictItem`.
1668    pub fn expr(self) -> Expr<'a> {
1669        self.0.cast_last()
1670    }
1671}
1672
1673node! {
1674    /// A spread: `..x` or `..x.at(0)`.
1675    struct Spread
1676}
1677
1678impl<'a> Spread<'a> {
1679    /// The spread expression.
1680    ///
1681    /// This should only be accessed if this `Spread` is contained in an
1682    /// `ArrayItem`, `DictItem`, or `Arg`.
1683    pub fn expr(self) -> Expr<'a> {
1684        self.0.cast_first()
1685    }
1686
1687    /// The sink identifier, if present.
1688    ///
1689    /// This should only be accessed if this `Spread` is contained in a
1690    /// `Param` or binding `DestructuringItem`.
1691    pub fn sink_ident(self) -> Option<Ident<'a>> {
1692        self.0.try_cast_first()
1693    }
1694
1695    /// The sink expressions, if present.
1696    ///
1697    /// This should only be accessed if this `Spread` is contained in a
1698    /// `DestructuringItem`.
1699    pub fn sink_expr(self) -> Option<Expr<'a>> {
1700        self.0.try_cast_first()
1701    }
1702}
1703
1704node! {
1705    /// A unary operation: `-x`.
1706    struct Unary
1707}
1708
1709impl<'a> Unary<'a> {
1710    /// The operator: `-`.
1711    pub fn op(self) -> UnOp {
1712        self.0
1713            .children()
1714            .find_map(|node| UnOp::from_kind(node.kind()))
1715            .unwrap_or(UnOp::Pos)
1716    }
1717
1718    /// The expression to operate on: `x`.
1719    pub fn expr(self) -> Expr<'a> {
1720        self.0.cast_last()
1721    }
1722}
1723
1724/// A unary operator.
1725#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1726pub enum UnOp {
1727    /// The plus operator: `+`.
1728    Pos,
1729    /// The negation operator: `-`.
1730    Neg,
1731    /// The boolean `not`.
1732    Not,
1733}
1734
1735impl UnOp {
1736    /// Try to convert the token into a unary operation.
1737    pub fn from_kind(token: SyntaxKind) -> Option<Self> {
1738        Some(match token {
1739            SyntaxKind::Plus => Self::Pos,
1740            SyntaxKind::Minus => Self::Neg,
1741            SyntaxKind::Not => Self::Not,
1742            _ => return Option::None,
1743        })
1744    }
1745
1746    /// The precedence of this operator.
1747    pub fn precedence(self) -> u8 {
1748        match self {
1749            Self::Pos | Self::Neg => 7,
1750            Self::Not => 4,
1751        }
1752    }
1753
1754    /// The string representation of this operation.
1755    pub fn as_str(self) -> &'static str {
1756        match self {
1757            Self::Pos => "+",
1758            Self::Neg => "-",
1759            Self::Not => "not",
1760        }
1761    }
1762}
1763
1764node! {
1765    /// A binary operation: `a + b`.
1766    struct Binary
1767}
1768
1769impl<'a> Binary<'a> {
1770    /// The binary operator: `+`.
1771    pub fn op(self) -> BinOp {
1772        let mut not = false;
1773        self.0
1774            .children()
1775            .find_map(|node| match node.kind() {
1776                SyntaxKind::Not => {
1777                    not = true;
1778                    Option::None
1779                }
1780                SyntaxKind::In if not => Some(BinOp::NotIn),
1781                _ => BinOp::from_kind(node.kind()),
1782            })
1783            .unwrap_or(BinOp::Add)
1784    }
1785
1786    /// The left-hand side of the operation: `a`.
1787    pub fn lhs(self) -> Expr<'a> {
1788        self.0.cast_first()
1789    }
1790
1791    /// The right-hand side of the operation: `b`.
1792    pub fn rhs(self) -> Expr<'a> {
1793        self.0.cast_last()
1794    }
1795}
1796
1797/// A binary operator.
1798#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1799pub enum BinOp {
1800    /// The addition operator: `+`.
1801    Add,
1802    /// The subtraction operator: `-`.
1803    Sub,
1804    /// The multiplication operator: `*`.
1805    Mul,
1806    /// The division operator: `/`.
1807    Div,
1808    /// The short-circuiting boolean `and`.
1809    And,
1810    /// The short-circuiting boolean `or`.
1811    Or,
1812    /// The equality operator: `==`.
1813    Eq,
1814    /// The inequality operator: `!=`.
1815    Neq,
1816    /// The less-than operator: `<`.
1817    Lt,
1818    /// The less-than or equal operator: `<=`.
1819    Leq,
1820    /// The greater-than operator: `>`.
1821    Gt,
1822    /// The greater-than or equal operator: `>=`.
1823    Geq,
1824    /// The assignment operator: `=`.
1825    Assign,
1826    /// The containment operator: `in`.
1827    In,
1828    /// The inverse containment operator: `not in`.
1829    NotIn,
1830    /// The add-assign operator: `+=`.
1831    AddAssign,
1832    /// The subtract-assign operator: `-=`.
1833    SubAssign,
1834    /// The multiply-assign operator: `*=`.
1835    MulAssign,
1836    /// The divide-assign operator: `/=`.
1837    DivAssign,
1838}
1839
1840impl BinOp {
1841    /// Try to convert the token into a binary operation.
1842    pub fn from_kind(token: SyntaxKind) -> Option<Self> {
1843        Some(match token {
1844            SyntaxKind::Plus => Self::Add,
1845            SyntaxKind::Minus => Self::Sub,
1846            SyntaxKind::Star => Self::Mul,
1847            SyntaxKind::Slash => Self::Div,
1848            SyntaxKind::And => Self::And,
1849            SyntaxKind::Or => Self::Or,
1850            SyntaxKind::EqEq => Self::Eq,
1851            SyntaxKind::ExclEq => Self::Neq,
1852            SyntaxKind::Lt => Self::Lt,
1853            SyntaxKind::LtEq => Self::Leq,
1854            SyntaxKind::Gt => Self::Gt,
1855            SyntaxKind::GtEq => Self::Geq,
1856            SyntaxKind::Eq => Self::Assign,
1857            SyntaxKind::In => Self::In,
1858            SyntaxKind::PlusEq => Self::AddAssign,
1859            SyntaxKind::HyphEq => Self::SubAssign,
1860            SyntaxKind::StarEq => Self::MulAssign,
1861            SyntaxKind::SlashEq => Self::DivAssign,
1862            _ => return Option::None,
1863        })
1864    }
1865
1866    /// The precedence of this operator.
1867    pub fn precedence(self) -> u8 {
1868        match self {
1869            Self::Mul => 6,
1870            Self::Div => 6,
1871            Self::Add => 5,
1872            Self::Sub => 5,
1873            Self::Eq => 4,
1874            Self::Neq => 4,
1875            Self::Lt => 4,
1876            Self::Leq => 4,
1877            Self::Gt => 4,
1878            Self::Geq => 4,
1879            Self::In => 4,
1880            Self::NotIn => 4,
1881            Self::And => 3,
1882            Self::Or => 2,
1883            Self::Assign => 1,
1884            Self::AddAssign => 1,
1885            Self::SubAssign => 1,
1886            Self::MulAssign => 1,
1887            Self::DivAssign => 1,
1888        }
1889    }
1890
1891    /// The associativity of this operator.
1892    pub fn assoc(self) -> Assoc {
1893        match self {
1894            Self::Add => Assoc::Left,
1895            Self::Sub => Assoc::Left,
1896            Self::Mul => Assoc::Left,
1897            Self::Div => Assoc::Left,
1898            Self::And => Assoc::Left,
1899            Self::Or => Assoc::Left,
1900            Self::Eq => Assoc::Left,
1901            Self::Neq => Assoc::Left,
1902            Self::Lt => Assoc::Left,
1903            Self::Leq => Assoc::Left,
1904            Self::Gt => Assoc::Left,
1905            Self::Geq => Assoc::Left,
1906            Self::In => Assoc::Left,
1907            Self::NotIn => Assoc::Left,
1908            Self::Assign => Assoc::Right,
1909            Self::AddAssign => Assoc::Right,
1910            Self::SubAssign => Assoc::Right,
1911            Self::MulAssign => Assoc::Right,
1912            Self::DivAssign => Assoc::Right,
1913        }
1914    }
1915
1916    /// The string representation of this operation.
1917    pub fn as_str(self) -> &'static str {
1918        match self {
1919            Self::Add => "+",
1920            Self::Sub => "-",
1921            Self::Mul => "*",
1922            Self::Div => "/",
1923            Self::And => "and",
1924            Self::Or => "or",
1925            Self::Eq => "==",
1926            Self::Neq => "!=",
1927            Self::Lt => "<",
1928            Self::Leq => "<=",
1929            Self::Gt => ">",
1930            Self::Geq => ">=",
1931            Self::In => "in",
1932            Self::NotIn => "not in",
1933            Self::Assign => "=",
1934            Self::AddAssign => "+=",
1935            Self::SubAssign => "-=",
1936            Self::MulAssign => "*=",
1937            Self::DivAssign => "/=",
1938        }
1939    }
1940}
1941
1942/// The associativity of a binary operator.
1943#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1944pub enum Assoc {
1945    /// Left-associative: `a + b + c` is equivalent to `(a + b) + c`.
1946    Left,
1947    /// Right-associative: `a = b = c` is equivalent to `a = (b = c)`.
1948    Right,
1949}
1950
1951node! {
1952    /// A field access: `properties.age`.
1953    struct FieldAccess
1954}
1955
1956impl<'a> FieldAccess<'a> {
1957    /// The expression to access the field on.
1958    pub fn target(self) -> Expr<'a> {
1959        self.0.cast_first()
1960    }
1961
1962    /// The name of the field.
1963    pub fn field(self) -> Ident<'a> {
1964        self.0.cast_last()
1965    }
1966}
1967
1968node! {
1969    /// An invocation of a function or method: `f(x, y)`.
1970    struct FuncCall
1971}
1972
1973impl<'a> FuncCall<'a> {
1974    /// The function to call.
1975    pub fn callee(self) -> Expr<'a> {
1976        self.0.cast_first()
1977    }
1978
1979    /// The arguments to the function.
1980    pub fn args(self) -> Args<'a> {
1981        self.0.cast_last()
1982    }
1983}
1984
1985node! {
1986    /// A function call's argument list: `(12pt, y)`.
1987    struct Args
1988}
1989
1990impl<'a> Args<'a> {
1991    /// The positional and named arguments.
1992    pub fn items(self) -> impl DoubleEndedIterator<Item = Arg<'a>> {
1993        self.0.children().filter_map(SyntaxNode::cast)
1994    }
1995
1996    /// Whether there is a comma at the end.
1997    pub fn trailing_comma(self) -> bool {
1998        self.0
1999            .children()
2000            .rev()
2001            .skip(1)
2002            .find(|n| !n.kind().is_trivia())
2003            .is_some_and(|n| n.kind() == SyntaxKind::Comma)
2004    }
2005}
2006
2007/// An argument to a function call.
2008#[derive(Debug, Copy, Clone, Hash)]
2009pub enum Arg<'a> {
2010    /// A positional argument: `12`.
2011    Pos(Expr<'a>),
2012    /// A named argument: `draw: false`.
2013    Named(Named<'a>),
2014    /// A spread argument: `..things`.
2015    Spread(Spread<'a>),
2016}
2017
2018impl<'a> AstNode<'a> for Arg<'a> {
2019    fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
2020        match node.kind() {
2021            SyntaxKind::Named => Some(Self::Named(Named(node))),
2022            SyntaxKind::Spread => Some(Self::Spread(Spread(node))),
2023            _ => node.cast().map(Self::Pos),
2024        }
2025    }
2026
2027    fn to_untyped(self) -> &'a SyntaxNode {
2028        match self {
2029            Self::Pos(v) => v.to_untyped(),
2030            Self::Named(v) => v.to_untyped(),
2031            Self::Spread(v) => v.to_untyped(),
2032        }
2033    }
2034
2035    fn placeholder() -> Self {
2036        Self::Pos(Expr::placeholder())
2037    }
2038}
2039
2040node! {
2041    /// A closure: `(x, y) => z`.
2042    struct Closure
2043}
2044
2045impl<'a> Closure<'a> {
2046    /// The name of the closure.
2047    ///
2048    /// This only exists if you use the function syntax sugar: `let f(x) = y`.
2049    pub fn name(self) -> Option<Ident<'a>> {
2050        self.0.children().next()?.cast()
2051    }
2052
2053    /// The parameter bindings.
2054    pub fn params(self) -> Params<'a> {
2055        self.0.cast_first()
2056    }
2057
2058    /// The body of the closure.
2059    pub fn body(self) -> Expr<'a> {
2060        self.0.cast_last()
2061    }
2062}
2063
2064node! {
2065    /// A closure's parameters: `(x, y)`.
2066    struct Params
2067}
2068
2069impl<'a> Params<'a> {
2070    /// The parameter bindings.
2071    pub fn children(self) -> impl DoubleEndedIterator<Item = Param<'a>> {
2072        self.0.children().filter_map(SyntaxNode::cast)
2073    }
2074}
2075
2076/// A parameter to a closure.
2077#[derive(Debug, Copy, Clone, Hash)]
2078pub enum Param<'a> {
2079    /// A positional parameter: `x`.
2080    Pos(Pattern<'a>),
2081    /// A named parameter with a default value: `draw: false`.
2082    Named(Named<'a>),
2083    /// An argument sink: `..args` or `..`.
2084    Spread(Spread<'a>),
2085}
2086
2087impl<'a> AstNode<'a> for Param<'a> {
2088    fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
2089        match node.kind() {
2090            SyntaxKind::Named => Some(Self::Named(Named(node))),
2091            SyntaxKind::Spread => Some(Self::Spread(Spread(node))),
2092            _ => node.cast().map(Self::Pos),
2093        }
2094    }
2095
2096    fn to_untyped(self) -> &'a SyntaxNode {
2097        match self {
2098            Self::Pos(v) => v.to_untyped(),
2099            Self::Named(v) => v.to_untyped(),
2100            Self::Spread(v) => v.to_untyped(),
2101        }
2102    }
2103
2104    fn placeholder() -> Self {
2105        Self::Pos(Pattern::placeholder())
2106    }
2107}
2108
2109/// The kind of a pattern.
2110#[derive(Debug, Copy, Clone, Hash)]
2111pub enum Pattern<'a> {
2112    /// A single expression: `x`.
2113    Normal(Expr<'a>),
2114    /// A placeholder: `_`.
2115    Placeholder(Underscore<'a>),
2116    /// A parenthesized pattern.
2117    Parenthesized(Parenthesized<'a>),
2118    /// A destructuring pattern: `(x, _, ..y)`.
2119    Destructuring(Destructuring<'a>),
2120}
2121
2122impl<'a> AstNode<'a> for Pattern<'a> {
2123    fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
2124        match node.kind() {
2125            SyntaxKind::Underscore => Some(Self::Placeholder(Underscore(node))),
2126            SyntaxKind::Parenthesized => Some(Self::Parenthesized(Parenthesized(node))),
2127            SyntaxKind::Destructuring => Some(Self::Destructuring(Destructuring(node))),
2128            _ => node.cast().map(Self::Normal),
2129        }
2130    }
2131
2132    fn to_untyped(self) -> &'a SyntaxNode {
2133        match self {
2134            Self::Normal(v) => v.to_untyped(),
2135            Self::Placeholder(v) => v.to_untyped(),
2136            Self::Parenthesized(v) => v.to_untyped(),
2137            Self::Destructuring(v) => v.to_untyped(),
2138        }
2139    }
2140
2141    fn placeholder() -> Self {
2142        Self::Normal(Expr::placeholder())
2143    }
2144}
2145
2146impl<'a> Pattern<'a> {
2147    /// Returns a list of all new bindings introduced by the pattern.
2148    pub fn bindings(self) -> Vec<Ident<'a>> {
2149        match self {
2150            Self::Normal(Expr::Ident(ident)) => vec![ident],
2151            Self::Parenthesized(v) => v.pattern().bindings(),
2152            Self::Destructuring(v) => v.bindings(),
2153            _ => vec![],
2154        }
2155    }
2156}
2157
2158node! {
2159    /// An underscore: `_`
2160    struct Underscore
2161}
2162
2163node! {
2164    /// A destructuring pattern: `x` or `(x, _, ..y)`.
2165    struct Destructuring
2166}
2167
2168impl<'a> Destructuring<'a> {
2169    /// The items of the destructuring.
2170    pub fn items(self) -> impl DoubleEndedIterator<Item = DestructuringItem<'a>> {
2171        self.0.children().filter_map(SyntaxNode::cast)
2172    }
2173
2174    /// Returns a list of all new bindings introduced by the destructuring.
2175    pub fn bindings(self) -> Vec<Ident<'a>> {
2176        self.items()
2177            .flat_map(|binding| match binding {
2178                DestructuringItem::Pattern(pattern) => pattern.bindings(),
2179                DestructuringItem::Named(named) => named.pattern().bindings(),
2180                DestructuringItem::Spread(spread) => {
2181                    spread.sink_ident().into_iter().collect()
2182                }
2183            })
2184            .collect()
2185    }
2186}
2187
2188/// The kind of an element in a destructuring pattern.
2189#[derive(Debug, Copy, Clone, Hash)]
2190pub enum DestructuringItem<'a> {
2191    /// A sub-pattern: `x`.
2192    Pattern(Pattern<'a>),
2193    /// A renamed destructuring: `x: y`.
2194    Named(Named<'a>),
2195    /// A destructuring sink: `..y` or `..`.
2196    Spread(Spread<'a>),
2197}
2198
2199impl<'a> AstNode<'a> for DestructuringItem<'a> {
2200    fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
2201        match node.kind() {
2202            SyntaxKind::Named => Some(Self::Named(Named(node))),
2203            SyntaxKind::Spread => Some(Self::Spread(Spread(node))),
2204            _ => node.cast().map(Self::Pattern),
2205        }
2206    }
2207
2208    fn to_untyped(self) -> &'a SyntaxNode {
2209        match self {
2210            Self::Pattern(v) => v.to_untyped(),
2211            Self::Named(v) => v.to_untyped(),
2212            Self::Spread(v) => v.to_untyped(),
2213        }
2214    }
2215
2216    fn placeholder() -> Self {
2217        Self::Pattern(Pattern::placeholder())
2218    }
2219}
2220
2221node! {
2222    /// A let binding: `let x = 1`.
2223    struct LetBinding
2224}
2225
2226/// The kind of a let binding, either a normal one or a closure.
2227#[derive(Debug)]
2228pub enum LetBindingKind<'a> {
2229    /// A normal binding: `let x = 1`.
2230    Normal(Pattern<'a>),
2231    /// A closure binding: `let f(x) = 1`.
2232    Closure(Ident<'a>),
2233}
2234
2235impl<'a> LetBindingKind<'a> {
2236    /// Returns a list of all new bindings introduced by the let binding.
2237    pub fn bindings(self) -> Vec<Ident<'a>> {
2238        match self {
2239            LetBindingKind::Normal(pattern) => pattern.bindings(),
2240            LetBindingKind::Closure(ident) => vec![ident],
2241        }
2242    }
2243}
2244
2245impl<'a> LetBinding<'a> {
2246    /// The kind of the let binding.
2247    pub fn kind(self) -> LetBindingKind<'a> {
2248        match self.0.cast_first() {
2249            Pattern::Normal(Expr::Closure(closure)) => {
2250                LetBindingKind::Closure(closure.name().unwrap_or_else(Ident::placeholder))
2251            }
2252            pattern => LetBindingKind::Normal(pattern),
2253        }
2254    }
2255
2256    /// The expression the binding is initialized with.
2257    pub fn init(self) -> Option<Expr<'a>> {
2258        match self.kind() {
2259            LetBindingKind::Normal(Pattern::Normal(_) | Pattern::Parenthesized(_)) => {
2260                self.0.children().filter_map(SyntaxNode::cast).nth(1)
2261            }
2262            LetBindingKind::Normal(_) => self.0.try_cast_first(),
2263            LetBindingKind::Closure(_) => self.0.try_cast_first(),
2264        }
2265    }
2266}
2267
2268node! {
2269    /// An assignment expression `(x, y) = (1, 2)`.
2270    struct DestructAssignment
2271}
2272
2273impl<'a> DestructAssignment<'a> {
2274    /// The pattern of the assignment.
2275    pub fn pattern(self) -> Pattern<'a> {
2276        self.0.cast_first()
2277    }
2278
2279    /// The expression that is assigned.
2280    pub fn value(self) -> Expr<'a> {
2281        self.0.cast_last()
2282    }
2283}
2284
2285node! {
2286    /// A set rule: `set text(...)`.
2287    struct SetRule
2288}
2289
2290impl<'a> SetRule<'a> {
2291    /// The function to set style properties for.
2292    pub fn target(self) -> Expr<'a> {
2293        self.0.cast_first()
2294    }
2295
2296    /// The style properties to set.
2297    pub fn args(self) -> Args<'a> {
2298        self.0.cast_last()
2299    }
2300
2301    /// A condition under which the set rule applies.
2302    pub fn condition(self) -> Option<Expr<'a>> {
2303        self.0
2304            .children()
2305            .skip_while(|child| child.kind() != SyntaxKind::If)
2306            .find_map(SyntaxNode::cast)
2307    }
2308}
2309
2310node! {
2311    /// A show rule: `show heading: it => emph(it.body)`.
2312    struct ShowRule
2313}
2314
2315impl<'a> ShowRule<'a> {
2316    /// Defines which nodes the show rule applies to.
2317    pub fn selector(self) -> Option<Expr<'a>> {
2318        self.0
2319            .children()
2320            .rev()
2321            .skip_while(|child| child.kind() != SyntaxKind::Colon)
2322            .find_map(SyntaxNode::cast)
2323    }
2324
2325    /// The transformation recipe.
2326    pub fn transform(self) -> Expr<'a> {
2327        self.0.cast_last()
2328    }
2329}
2330
2331node! {
2332    /// A contextual expression: `context text.lang`.
2333    struct Contextual
2334}
2335
2336impl<'a> Contextual<'a> {
2337    /// The expression which depends on the context.
2338    pub fn body(self) -> Expr<'a> {
2339        self.0.cast_first()
2340    }
2341}
2342
2343node! {
2344    /// An if-else conditional: `if x { y } else { z }`.
2345    struct Conditional
2346}
2347
2348impl<'a> Conditional<'a> {
2349    /// The condition which selects the body to evaluate.
2350    pub fn condition(self) -> Expr<'a> {
2351        self.0.cast_first()
2352    }
2353
2354    /// The expression to evaluate if the condition is true.
2355    pub fn if_body(self) -> Expr<'a> {
2356        self.0
2357            .children()
2358            .filter_map(SyntaxNode::cast)
2359            .nth(1)
2360            .unwrap_or_else(Expr::placeholder)
2361    }
2362
2363    /// The expression to evaluate if the condition is false.
2364    pub fn else_body(self) -> Option<Expr<'a>> {
2365        self.0.children().filter_map(SyntaxNode::cast).nth(2)
2366    }
2367}
2368
2369node! {
2370    /// A while loop: `while x { y }`.
2371    struct WhileLoop
2372}
2373
2374impl<'a> WhileLoop<'a> {
2375    /// The condition which selects whether to evaluate the body.
2376    pub fn condition(self) -> Expr<'a> {
2377        self.0.cast_first()
2378    }
2379
2380    /// The expression to evaluate while the condition is true.
2381    pub fn body(self) -> Expr<'a> {
2382        self.0.cast_last()
2383    }
2384}
2385
2386node! {
2387    /// A for loop: `for x in y { z }`.
2388    struct ForLoop
2389}
2390
2391impl<'a> ForLoop<'a> {
2392    /// The pattern to assign to.
2393    pub fn pattern(self) -> Pattern<'a> {
2394        self.0.cast_first()
2395    }
2396
2397    /// The expression to iterate over.
2398    pub fn iterable(self) -> Expr<'a> {
2399        self.0
2400            .children()
2401            .skip_while(|&c| c.kind() != SyntaxKind::In)
2402            .find_map(SyntaxNode::cast)
2403            .unwrap_or_else(Expr::placeholder)
2404    }
2405
2406    /// The expression to evaluate for each iteration.
2407    pub fn body(self) -> Expr<'a> {
2408        self.0.cast_last()
2409    }
2410}
2411
2412node! {
2413    /// A module import: `import "utils.typ": a, b, c`.
2414    struct ModuleImport
2415}
2416
2417impl<'a> ModuleImport<'a> {
2418    /// The module or path from which the items should be imported.
2419    pub fn source(self) -> Expr<'a> {
2420        self.0.cast_first()
2421    }
2422
2423    /// The items to be imported.
2424    pub fn imports(self) -> Option<Imports<'a>> {
2425        self.0.children().find_map(|node| match node.kind() {
2426            SyntaxKind::Star => Some(Imports::Wildcard),
2427            SyntaxKind::ImportItems => node.cast().map(Imports::Items),
2428            _ => Option::None,
2429        })
2430    }
2431
2432    /// The name that will be bound for a bare import. This name must be
2433    /// statically known. It can come from:
2434    /// - an identifier
2435    /// - a field access
2436    /// - a string that is a valid file path where the file stem is a valid
2437    ///   identifier
2438    /// - a string that is a valid package spec
2439    pub fn bare_name(self) -> Result<EcoString, BareImportError> {
2440        match self.source() {
2441            Expr::Ident(ident) => Ok(ident.get().clone()),
2442            Expr::FieldAccess(access) => Ok(access.field().get().clone()),
2443            Expr::Str(string) => {
2444                let string = string.get();
2445                let name = if string.starts_with('@') {
2446                    PackageSpec::from_str(&string)
2447                        .map_err(|_| BareImportError::PackageInvalid)?
2448                        .name
2449                } else {
2450                    Path::new(string.as_str())
2451                        .file_stem()
2452                        .and_then(|path| path.to_str())
2453                        .ok_or(BareImportError::PathInvalid)?
2454                        .into()
2455                };
2456
2457                if !is_ident(&name) {
2458                    return Err(BareImportError::PathInvalid);
2459                }
2460
2461                Ok(name)
2462            }
2463            _ => Err(BareImportError::Dynamic),
2464        }
2465    }
2466
2467    /// The name this module was assigned to, if it was renamed with `as`
2468    /// (`renamed` in `import "..." as renamed`).
2469    pub fn new_name(self) -> Option<Ident<'a>> {
2470        self.0
2471            .children()
2472            .skip_while(|child| child.kind() != SyntaxKind::As)
2473            .find_map(SyntaxNode::cast)
2474    }
2475}
2476
2477/// Reasons why a bare name cannot be determined for an import source.
2478#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
2479pub enum BareImportError {
2480    /// There is no statically resolvable binding name.
2481    Dynamic,
2482    /// The import source is not a valid path or the path stem not a valid
2483    /// identifier.
2484    PathInvalid,
2485    /// The import source is not a valid package spec.
2486    PackageInvalid,
2487}
2488
2489/// The items that ought to be imported from a file.
2490#[derive(Debug, Copy, Clone, Hash)]
2491pub enum Imports<'a> {
2492    /// All items in the scope of the file should be imported.
2493    Wildcard,
2494    /// The specified items from the file should be imported.
2495    Items(ImportItems<'a>),
2496}
2497
2498node! {
2499    /// Items to import from a module: `a, b, c`.
2500    struct ImportItems
2501}
2502
2503impl<'a> ImportItems<'a> {
2504    /// Returns an iterator over the items to import from the module.
2505    pub fn iter(self) -> impl DoubleEndedIterator<Item = ImportItem<'a>> {
2506        self.0.children().filter_map(|child| match child.kind() {
2507            SyntaxKind::RenamedImportItem => child.cast().map(ImportItem::Renamed),
2508            SyntaxKind::ImportItemPath => child.cast().map(ImportItem::Simple),
2509            _ => Option::None,
2510        })
2511    }
2512}
2513
2514node! {
2515    /// A path to a submodule's imported name: `a.b.c`.
2516    struct ImportItemPath
2517}
2518
2519impl<'a> ImportItemPath<'a> {
2520    /// An iterator over the path's components.
2521    pub fn iter(self) -> impl DoubleEndedIterator<Item = Ident<'a>> {
2522        self.0.children().filter_map(SyntaxNode::cast)
2523    }
2524
2525    /// The name of the imported item. This is the last segment in the path.
2526    pub fn name(self) -> Ident<'a> {
2527        self.0.cast_last()
2528    }
2529}
2530
2531/// An imported item, potentially renamed to another identifier.
2532#[derive(Debug, Copy, Clone, Hash)]
2533pub enum ImportItem<'a> {
2534    /// A non-renamed import (the item's name in the scope is the same as its
2535    /// name).
2536    Simple(ImportItemPath<'a>),
2537    /// A renamed import (the item was bound to a different name in the scope
2538    /// than the one it was defined as).
2539    Renamed(RenamedImportItem<'a>),
2540}
2541
2542impl<'a> ImportItem<'a> {
2543    /// The path to the imported item.
2544    pub fn path(self) -> ImportItemPath<'a> {
2545        match self {
2546            Self::Simple(path) => path,
2547            Self::Renamed(renamed_item) => renamed_item.path(),
2548        }
2549    }
2550
2551    /// The original name of the imported item, at its source. This will be the
2552    /// equal to the bound name if the item wasn't renamed with 'as'.
2553    pub fn original_name(self) -> Ident<'a> {
2554        match self {
2555            Self::Simple(path) => path.name(),
2556            Self::Renamed(renamed_item) => renamed_item.original_name(),
2557        }
2558    }
2559
2560    /// The name which this import item was bound to. Corresponds to the new
2561    /// name, if it was renamed; otherwise, it's just its original name.
2562    pub fn bound_name(self) -> Ident<'a> {
2563        match self {
2564            Self::Simple(path) => path.name(),
2565            Self::Renamed(renamed_item) => renamed_item.new_name(),
2566        }
2567    }
2568}
2569
2570node! {
2571    /// A renamed import item: `a as d`
2572    struct RenamedImportItem
2573}
2574
2575impl<'a> RenamedImportItem<'a> {
2576    /// The path to the imported item.
2577    pub fn path(self) -> ImportItemPath<'a> {
2578        self.0.cast_first()
2579    }
2580
2581    /// The original name of the imported item (`a` in `a as d` or `c.b.a as d`).
2582    pub fn original_name(self) -> Ident<'a> {
2583        self.path().name()
2584    }
2585
2586    /// The new name of the imported item (`d` in `a as d`).
2587    pub fn new_name(self) -> Ident<'a> {
2588        self.0.cast_last()
2589    }
2590}
2591
2592node! {
2593    /// A module include: `include "chapter1.typ"`.
2594    struct ModuleInclude
2595}
2596
2597impl<'a> ModuleInclude<'a> {
2598    /// The module or path from which the content should be included.
2599    pub fn source(self) -> Expr<'a> {
2600        self.0.cast_last()
2601    }
2602}
2603
2604node! {
2605    /// A break from a loop: `break`.
2606    struct LoopBreak
2607}
2608
2609node! {
2610    /// A continue in a loop: `continue`.
2611    struct LoopContinue
2612}
2613
2614node! {
2615    /// A return from a function: `return`, `return x + 1`.
2616    struct FuncReturn
2617}
2618
2619impl<'a> FuncReturn<'a> {
2620    /// The expression to return.
2621    pub fn body(self) -> Option<Expr<'a>> {
2622        self.0.try_cast_last()
2623    }
2624}
2625
2626#[cfg(test)]
2627mod tests {
2628    use super::*;
2629
2630    #[test]
2631    fn test_expr_placeholder() {
2632        assert!(Expr::placeholder().to_untyped().cast::<Expr>().is_some());
2633    }
2634}