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