Skip to main content

i_slint_compiler/
parser.rs

1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4// cSpell: ignore nodekind
5/*! The Slint Language Parser
6
7This module is responsible to parse a string onto a syntax tree.
8
9The core of it is the `DefaultParser` class that holds a list of token and
10generates a `rowan::GreenNode`
11
12This module has different sub modules with the actual parser functions
13
14*/
15
16use crate::diagnostics::{BuildDiagnostics, SourceFile, Spanned};
17use smol_str::SmolStr;
18use std::fmt::Display;
19
20mod document;
21mod element;
22mod expressions;
23mod statements;
24mod r#type;
25
26/// Each parser submodule would simply do `use super::prelude::*` to import typically used items
27mod prelude {
28    #[cfg(test)]
29    pub use super::DefaultParser;
30    pub use super::{Parser, SyntaxKind};
31    #[cfg(test)]
32    pub use super::{SyntaxNode, SyntaxNodeVerify, syntax_nodes};
33    #[cfg(test)]
34    pub use i_slint_parser_test_macro::parser_test;
35}
36
37#[cfg(test)]
38pub trait SyntaxNodeVerify {
39    /// The SyntaxKind corresponding to this type
40    const KIND: SyntaxKind;
41    /// Asserts that the node is of the given SyntaxKind and that it has the expected children
42    /// Panic if this is not the case
43    fn verify(node: SyntaxNode) {
44        assert_eq!(node.kind(), Self::KIND)
45    }
46}
47
48pub use rowan::{TextRange, TextSize};
49
50/// Check that a node has the assumed children
51#[cfg(test)]
52macro_rules! verify_node {
53    // Some combination of children
54    ($node:ident, [ $($t1:tt $($t2:ident)?),* ]) => {
55        // Check that every children is there
56        $(verify_node!(@check_has_children $node, $t1 $($t2)* );)*
57
58        // check that there are not too many nodes
59        for c in $node.children() {
60            assert!(
61                false $(|| c.kind() == verify_node!(@extract_kind $t1 $($t2)*))*,
62                "Node is none of [{}]\n{:?}", stringify!($($t1 $($t2)*),*) ,c);
63        }
64
65        // recurse
66        $(
67            for _c in $node.children().filter(|n| n.kind() == verify_node!(@extract_kind $t1 $($t2)*)) {
68                <verify_node!(@extract_type $t1 $($t2)*)>::verify(_c)
69            }
70        )*
71    };
72
73    // At least one
74    (@check_has_children $node:ident, + $kind:ident) => {
75        let count = $node.children_with_tokens().filter(|n| n.kind() == SyntaxKind::$kind).count();
76        assert!(count >= 1, "Expecting one or more sub-node of type {}, found {}\n{:?}", stringify!($kind), count, $node);
77    };
78    // Any number of this kind.
79    (@check_has_children $node:ident, * $kind:ident) => {};
80    // 1 or 0
81    (@check_has_children $node:ident, ? $kind:ident) => {
82        let count = $node.children_with_tokens().filter(|n| n.kind() == SyntaxKind::$kind).count();
83        assert!(count <= 1, "Expecting one or zero sub-node of type {}, found {}\n{:?}", stringify!($kind), count, $node);
84    };
85    // Exactly one
86    (@check_has_children $node:ident, $kind:ident) => {
87        let count = $node.children_with_tokens().filter(|n| n.kind() == SyntaxKind::$kind).count();
88        assert_eq!(count, 1, "Expecting exactly one sub-node of type {}\n{:?}", stringify!($kind), $node);
89    };
90    // Exact number
91    (@check_has_children $node:ident, $count:literal $kind:ident) => {
92        let count = $node.children_with_tokens().filter(|n| n.kind() == SyntaxKind::$kind).count();
93        assert_eq!(count, $count, "Expecting {} sub-node of type {}, found {}\n{:?}", $count, stringify!($kind), count, $node);
94    };
95
96    (@extract_kind + $kind:ident) => {SyntaxKind::$kind};
97    (@extract_kind * $kind:ident) => {SyntaxKind::$kind};
98    (@extract_kind ? $kind:ident) => {SyntaxKind::$kind};
99    (@extract_kind $count:literal $kind:ident) => {SyntaxKind::$kind};
100    (@extract_kind $kind:ident) => {SyntaxKind::$kind};
101
102    (@extract_type + $kind:ident) => {$crate::parser::syntax_nodes::$kind};
103    (@extract_type * $kind:ident) => {$crate::parser::syntax_nodes::$kind};
104    (@extract_type ? $kind:ident) => {$crate::parser::syntax_nodes::$kind};
105    (@extract_type $count:literal $kind:ident) => {$crate::parser::syntax_nodes::$kind};
106    (@extract_type $kind:ident) => {$crate::parser::syntax_nodes::$kind};
107}
108
109macro_rules! node_accessors {
110    // Some combination of children
111    ([ $($t1:tt $($t2:ident)?),* ]) => {
112        $(node_accessors!{@ $t1 $($t2)*} )*
113    };
114    (@ + $kind:ident) => {
115        #[allow(non_snake_case)]
116        pub fn $kind(&self) -> impl Iterator<Item = $kind> + use<> {
117            let mut it = self.0.children().filter(|n| n.kind() == SyntaxKind::$kind).map(Into::into).peekable();
118            debug_assert!(it.peek().is_some(), stringify!(Expected at least one $kind));
119            it
120        }
121    };
122    (@ * $kind:ident) => {
123        #[allow(non_snake_case)]
124        pub fn $kind(&self) -> impl Iterator<Item = $kind> + use<> {
125            self.0.children().filter(|n| n.kind() == SyntaxKind::$kind).map(Into::into)
126        }
127    };
128    (@ ? $kind:ident) => {
129        #[allow(non_snake_case)]
130        pub fn $kind(&self) -> Option<$kind> {
131            self.0.child_node(SyntaxKind::$kind).map(Into::into)
132        }
133    };
134    (@ 2 $kind:ident) => {
135        #[allow(non_snake_case)]
136        #[track_caller]
137        pub fn $kind(&self) -> ($kind, $kind) {
138            let mut it = self.0.children().filter(|n| n.kind() == SyntaxKind::$kind);
139            let a = it.next().expect(stringify!(Missing first $kind));
140            let b = it.next().expect(stringify!(Missing second $kind));
141            debug_assert!(it.next().is_none(), stringify!(More $kind than expected));
142            (a.into(), b.into())
143        }
144    };
145    (@ 3 $kind:ident) => {
146        #[allow(non_snake_case)]
147        #[track_caller]
148        pub fn $kind(&self) -> ($kind, $kind, $kind) {
149            let mut it = self.0.children().filter(|n| n.kind() == SyntaxKind::$kind);
150            let a = it.next().expect(stringify!(Missing first $kind));
151            let b = it.next().expect(stringify!(Missing second $kind));
152            let c = it.next().expect(stringify!(Missing third $kind));
153            debug_assert!(it.next().is_none(), stringify!(More $kind than expected));
154            (a.into(), b.into(), c.into())
155        }
156    };
157    (@ $kind:ident) => {
158        #[allow(non_snake_case)]
159        #[track_caller]
160        pub fn $kind(&self) -> $kind {
161            self.0.child_node(SyntaxKind::$kind).expect(stringify!(Missing $kind)).into()
162        }
163    };
164
165}
166
167/// This macro is invoked once, to declare all the token and syntax kind.
168/// The purpose of this macro is to declare the token with its regexp at the same place,
169/// and the nodes with their contents.
170///
171/// This is split into two group: first the tokens, then the nodes.
172///
173/// # Tokens
174///
175/// Given as `$token:ident -> $rule:expr`. The rule parameter can be either a string literal or
176/// a lexer function. The order of tokens is important because the rules will be run in that order
177/// and the first one matching will be chosen.
178///
179/// # Nodes
180///
181/// Given as `$(#[$attr:meta])* $nodekind:ident -> [$($children:tt),*] `.
182/// Where `children` is a list of sub-nodes (not including tokens).
183/// This will allow to self-document and create the structure from the [`syntax_nodes`] module.
184/// The children can be prefixed with the following symbol:
185///
186/// - nothing: The node occurs once and exactly once, the generated accessor returns the node itself
187/// - `+`: the node occurs one or several times, the generated accessor returns an `Iterator`
188/// - `*`: the node occurs zero or several times, the generated accessor returns an `Iterator`
189/// - `?`: the node occurs once or zero times, the generated accessor returns an `Option`
190/// - `2` or `3`: the node occurs exactly two or three times, the generated accessor returns a tuple
191///
192/// Note: the parser must generate the right amount of sub nodes, even if there is a parse error.
193///
194/// ## The [`syntax_nodes`] module
195///
196/// Creates one struct for every node with the given accessor.
197/// The struct can be converted from and to the node.
198macro_rules! declare_syntax {
199    ({
200        $($token:ident -> $rule:expr ,)*
201     }
202     {
203        $( $(#[$attr:meta])*  $nodekind:ident -> $children:tt ,)*
204    })
205    => {
206        #[repr(u16)]
207        #[derive(Debug, Copy, Clone, Eq, PartialEq, num_enum::IntoPrimitive, num_enum::TryFromPrimitive, Hash, Ord, PartialOrd)]
208        pub enum SyntaxKind {
209            Error,
210            Eof,
211
212            // Tokens:
213            $(
214                /// Token
215                $token,
216            )*
217
218            // Nodes:
219            $(
220                $(#[$attr])*
221                $nodekind,
222            )*
223        }
224
225        impl Display for SyntaxKind {
226            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
227                match self {
228                    $(Self::$token => {
229                        if let Some(character) = <dyn std::any::Any>::downcast_ref::<&str>(& $rule) {
230                            return write!(f, "'{}'", character)
231                        }
232                    })*
233                    _ => ()
234                }
235                write!(f, "{:?}", self)
236            }
237        }
238
239
240        /// Returns a pair of the matched token type at the beginning of `text`, and its size
241        pub fn lex_next_token(text : &str, state: &mut crate::lexer::LexState) -> Option<(usize, SyntaxKind)> {
242            use crate::lexer::LexingRule;
243            $(
244                let len = ($rule).lex(text, state);
245                if len > 0 {
246                    return Some((len, SyntaxKind::$token));
247                }
248            )*
249            None
250        }
251
252        pub mod syntax_nodes {
253            use super::*;
254            $(
255                #[derive(Debug, Clone, derive_more::Deref, derive_more::Into)]
256                pub struct $nodekind(SyntaxNode);
257                #[cfg(test)]
258                impl SyntaxNodeVerify for $nodekind {
259                    const KIND: SyntaxKind = SyntaxKind::$nodekind;
260                    #[track_caller]
261                    fn verify(node: SyntaxNode) {
262                        assert_eq!(node.kind(), Self::KIND);
263                        verify_node!(node, $children);
264                    }
265                }
266                impl $nodekind {
267                    node_accessors!{$children}
268
269                    /// Create a new node from a SyntaxNode, if the SyntaxNode is of the correct kind
270                    pub fn new(node: SyntaxNode) -> Option<Self> {
271                        (node.kind() == SyntaxKind::$nodekind).then(|| Self(node))
272                    }
273                }
274
275                impl From<SyntaxNode> for $nodekind {
276                    #[track_caller]
277                    fn from(node: SyntaxNode) -> Self {
278                        assert_eq!(node.kind(), SyntaxKind::$nodekind);
279                        Self(node)
280                    }
281                }
282
283                impl Spanned for $nodekind {
284                    fn span(&self) -> crate::diagnostics::Span {
285                        self.0.span()
286                    }
287
288                    fn source_file(&self) -> Option<&SourceFile> {
289                        self.0.source_file()
290                    }
291                }
292            )*
293        }
294    }
295}
296declare_syntax! {
297    // Tokens.
298    // WARNING: when changing this, do not forget to update the tokenizer in the slint-rs-macro crate!
299    // The order of token is important because the rules will be run in that order
300    // and the first one matching will be chosen.
301    {
302        Whitespace -> &crate::lexer::lex_whitespace,
303        Comment -> &crate::lexer::lex_comment,
304        StringLiteral -> &crate::lexer::lex_string,
305        NumberLiteral -> &crate::lexer::lex_number,
306        ColorLiteral -> &crate::lexer::lex_color,
307        Identifier -> &crate::lexer::lex_identifier,
308        DoubleArrow -> "<=>",
309        DoubleLess -> "<<",
310        PlusEqual -> "+=",
311        MinusEqual -> "-=",
312        StarEqual -> "*=",
313        DivEqual -> "/=",
314        LessEqual -> "<=",
315        GreaterEqual -> ">=",
316        EqualEqual -> "==",
317        NotEqual -> "!=",
318        ColonEqual -> ":=",
319        FatArrow -> "=>",
320        Arrow -> "->",
321        OrOr -> "||",
322        AndAnd -> "&&",
323        LBrace -> "{",
324        RBrace -> "}",
325        LParent -> "(",
326        RParent -> ")",
327        LAngle -> "<",
328        RAngle -> ">",
329        LBracket -> "[",
330        RBracket -> "]",
331        Plus -> "+",
332        Minus -> "-",
333        Star -> "*",
334        Div -> "/",
335        Equal -> "=",
336        Colon -> ":",
337        Comma -> ",",
338        Semicolon -> ";",
339        Bang -> "!",
340        Dot -> ".",
341        Question -> "?",
342        Dollar -> "$",
343        At -> "@",
344        Pipe -> "|",
345        Percent -> "%",
346    }
347    // Syntax Nodes. The list after the `->` is the possible child nodes,
348    // see the documentation of `declare_syntax!` macro for details.
349    {
350        Document -> [ *Component, *ExportsList, *ImportSpecifier, *StructDeclaration, *EnumDeclaration ],
351        /// `DeclaredIdentifier := Element { ... }`
352        Component -> [ DeclaredIdentifier, Element ],
353        /// `id := Element { ... }`
354        SubElement -> [ Element ],
355        Element -> [ ?QualifiedName, *PropertyDeclaration, *Binding, *CallbackConnection,
356                     *CallbackDeclaration, *ConditionalElement, *MatchElement, *Function, *SubElement,
357                     *RepeatedElement, *PropertyAnimation, *PropertyChangedCallback,
358                     *TwoWayBinding, *States, *Transitions, *ImplementStatement, ?ChildrenPlaceholder,
359                     *SlotDeclaration, *SlotAssignment, *SlotForwarding ],
360        RepeatedElement -> [ ?DeclaredIdentifier, ?RepeatedIndex, Expression , SubElement],
361        RepeatedIndex -> [],
362        ConditionalElement -> [ Expression , SubElement],
363        /// match (foo) { 1: Elem { } }
364        MatchElement -> [ Expression , *MatchCase, ?WildcardMatchCase ],
365        /// 1: Elem { }
366        MatchCase -> [ Expression, ?SubElement ],
367        /// *: Elem { }
368        WildcardMatchCase -> [ ?SubElement ],
369        CallbackDeclaration -> [ ?PropertyDeprecation, ?ShadowableAttribute, DeclaredIdentifier, *CallbackDeclarationParameter, ?ReturnType, ?TwoWayBinding ],
370        // `foo: type` or just `type`
371        CallbackDeclarationParameter -> [ ?DeclaredIdentifier, Type],
372        Function -> [ ?PropertyDeprecation, ?ShadowableAttribute, DeclaredIdentifier, *ArgumentDeclaration, ?ReturnType, ?CodeBlock ],
373        ArgumentDeclaration -> [DeclaredIdentifier, Type],
374        /// `-> type`  (but without the ->)
375        ReturnType -> [Type],
376        CallbackConnection -> [ *DeclaredIdentifier, ?CodeBlock, ?Expression ],
377        /// Declaration of a property.
378        PropertyDeclaration-> [ ?PropertyDeprecation, ?ShadowableAttribute, ?Type , DeclaredIdentifier, ?BindingExpression, ?TwoWayBinding ],
379        /// `@deprecated` or `@deprecated("message")` prefixing a member declaration.
380        /// The optional message is a StringLiteral token child.
381        PropertyDeprecation -> [],
382        /// `@shadowable` prefixing a property, callback or function declaration: a component
383        /// inheriting from this one may declare a member of the same name, shadowing this one.
384        ShadowableAttribute -> [],
385        /// QualifiedName are the properties name
386        PropertyAnimation-> [ *QualifiedName, *Binding ],
387        /// `changed xxx => {...}`  where `xxx` is the DeclaredIdentifier
388        PropertyChangedCallback-> [ DeclaredIdentifier, ?CodeBlock, ?Expression ],
389        /// wraps Identifiers, like `Rectangle` or `SomeModule.SomeType`
390        QualifiedName-> [],
391        /// Wraps single identifier (to disambiguate when there are other identifier in the production)
392        DeclaredIdentifier -> [],
393        ChildrenPlaceholder -> [],
394        SlotAssignment -> [ DeclaredIdentifier, SubElement ],
395        SlotForwarding -> [ DeclaredIdentifier, ?Expression ],
396        Binding-> [ BindingExpression ],
397        /// `xxx <=> something`
398        TwoWayBinding -> [ Expression ],
399        /// `implement Interface <=> target;`
400        ImplementStatement -> [ QualifiedName, DeclaredIdentifier ],
401        /// the right-hand-side of a binding
402        // Fixme: the test should be a or
403        BindingExpression-> [ ?CodeBlock, ?Expression ],
404        CodeBlock-> [ *Expression, *LetStatement, *ReturnStatement ],
405        LetStatement -> [ DeclaredIdentifier, ?Type, Expression ],
406        ReturnStatement -> [ ?Expression ],
407        // FIXME: the test should test that as alternative rather than several of them (but it can also be a literal)
408        Expression-> [ ?Expression, ?FunctionCallExpression, ?IndexExpression, ?SelfAssignment,
409                       ?ConditionalExpression, ?QualifiedName, ?BinaryExpression, ?Array, ?ObjectLiteral,
410                       ?UnaryOpExpression, ?CodeBlock, ?StringTemplate, ?AtImageUrl, ?AtGradient, ?AtTr,
411                       ?MemberAccess, ?AtKeys, ?Closure ],
412        /// Concatenate the children Expressions and StringLiteral to make a string
413        StringTemplate -> [*Expression],
414        /// `@image-url("foo.png")`
415        AtImageUrl -> [],
416        /// `@linear-gradient(...)` or `@radial-gradient(...)`
417        AtGradient -> [*Expression],
418        /// `@tr("foo", ...)`  // the string is a StringLiteral
419        AtTr -> [?TrContext, ?TrPlural, *Expression],
420        AtMarkdown -> [*Expression],
421        /// `slot header;`
422        SlotDeclaration -> [ DeclaredIdentifier ],
423        /// `"foo" =>`  in a `AtTr` node
424        TrContext -> [],
425        /// `| "foo" % n`  in a `AtTr` node
426        TrPlural -> [Expression],
427        /// `@keys(...)`
428        AtKeys -> [],
429        /// expression()
430        FunctionCallExpression -> [*Expression],
431        /// `expression[index]`
432        IndexExpression -> [2 Expression],
433        /// `expression += expression`
434        SelfAssignment -> [2 Expression],
435        /// `condition ? first : second`
436        ConditionalExpression -> [3 Expression],
437        /// `expr + expr`
438        BinaryExpression -> [2 Expression],
439        /// `- expr`
440        UnaryOpExpression -> [Expression],
441        /// `(foo).bar`, where `foo` is the base expression, and `bar` is a Identifier.
442        MemberAccess -> [Expression],
443        /// `[ ... ]`
444        Array -> [ *Expression ],
445        /// `{ foo: bar }`
446        ObjectLiteral -> [ *ObjectMember ],
447        /// `foo: bar` inside an ObjectLiteral
448        ObjectMember -> [ Expression ],
449        /// `states: [...]`
450        States -> [*State],
451        /// The DeclaredIdentifier is the state name. The Expression, if any, is the condition.
452        State -> [DeclaredIdentifier, ?Expression, *StatePropertyChange, *Transition],
453        /// binding within a state
454        StatePropertyChange -> [ QualifiedName, BindingExpression ],
455        /// `transitions: [...]`
456        Transitions -> [*Transition],
457        /// There is an identifier "in", "out", "in-out", the DeclaredIdentifier is the state name
458        Transition -> [?DeclaredIdentifier, *PropertyAnimation],
459        /// Export a set of declared components by name
460        ExportsList -> [ *ExportSpecifier, ?Component, *StructDeclaration, ?ExportModule, *EnumDeclaration ],
461        /// Declare the first identifier to be exported, either under its name or instead
462        /// under the name of the second identifier.
463        ExportSpecifier -> [ ExportIdentifier, ?ExportName ],
464        ExportIdentifier -> [],
465        ExportName -> [],
466        /// `export ... from "foo"`. The import uri is stored as string literal.
467        ExportModule -> [],
468        /// import { foo, bar, baz } from "blah"; The import uri is stored as string literal.
469        ImportSpecifier -> [ ?ImportIdentifierList ],
470        ImportIdentifierList -> [ *ImportIdentifier ],
471        /// { foo as bar } or just { foo }
472        ImportIdentifier -> [ ExternalName, ?InternalName ],
473        ExternalName -> [],
474        InternalName -> [],
475        /// The representation of a type
476        Type -> [ ?QualifiedName, ?ObjectType, ?ArrayType ],
477        /// `{foo: string, bar: string} `
478        ObjectType ->[ *ObjectTypeMember ],
479        /// `foo: type` or `foo: type = default-value` inside an ObjectType
480        ObjectTypeMember -> [ Type, ?Expression ],
481        /// `[ type ]`
482        ArrayType -> [ Type ],
483        /// `struct Foo { ... }`
484        StructDeclaration -> [DeclaredIdentifier, ObjectType, *AtRustAttr],
485        /// `enum Foo { bli, bla, blu }`
486        EnumDeclaration -> [DeclaredIdentifier, *EnumValue, *AtRustAttr],
487        /// The value is a Identifier
488        EnumValue -> [],
489        /// `@rust-attr(...)`
490        AtRustAttr -> [],
491        /// `(x) => x > 0`
492        Closure -> [DeclaredIdentifier, Expression],
493    }
494}
495
496impl From<SyntaxKind> for rowan::SyntaxKind {
497    fn from(v: SyntaxKind) -> Self {
498        rowan::SyntaxKind(v.into())
499    }
500}
501
502#[derive(Clone, Debug)]
503pub struct Token {
504    pub kind: SyntaxKind,
505    pub text: SmolStr,
506    /// Byte offset of `text` in the document, which is the concatenation of every token's text
507    pub offset: usize,
508    #[cfg(feature = "proc_macro_span")]
509    pub span: Option<proc_macro::Span>,
510}
511
512impl Default for Token {
513    fn default() -> Self {
514        Token {
515            kind: SyntaxKind::Eof,
516            text: Default::default(),
517            offset: 0,
518            #[cfg(feature = "proc_macro_span")]
519            span: None,
520        }
521    }
522}
523
524impl Token {
525    pub fn as_str(&self) -> &str {
526        self.text.as_str()
527    }
528
529    pub fn kind(&self) -> SyntaxKind {
530        self.kind
531    }
532}
533
534mod parser_trait {
535    //! module allowing to keep implementation details of the node private
536    use super::*;
537
538    pub trait Parser: Sized {
539        type Checkpoint: Clone;
540
541        /// Enter a new node.  The node is going to be finished when
542        /// The return value of this function is dropped
543        ///
544        /// (do not re-implement this function, re-implement
545        /// start_node_impl and finish_node_impl)
546        #[must_use = "The node will be finished when it is dropped"]
547        fn start_node(&mut self, kind: SyntaxKind) -> Node<'_, Self> {
548            self.start_node_impl(kind, None, NodeToken(()));
549            Node(self)
550        }
551        #[must_use = "use start_node_at to use this checkpoint"]
552        fn checkpoint(&mut self) -> Self::Checkpoint;
553        #[must_use = "The node will be finished when it is dropped"]
554        fn start_node_at(
555            &mut self,
556            checkpoint: impl Into<Option<Self::Checkpoint>>,
557            kind: SyntaxKind,
558        ) -> Node<'_, Self> {
559            self.start_node_impl(kind, checkpoint.into(), NodeToken(()));
560            Node(self)
561        }
562
563        /// Can only be called by Node::drop
564        fn finish_node_impl(&mut self, token: NodeToken);
565        /// Can only be called by Self::start_node
566        fn start_node_impl(
567            &mut self,
568            kind: SyntaxKind,
569            checkpoint: Option<Self::Checkpoint>,
570            token: NodeToken,
571        );
572
573        /// Same as nth(0)
574        fn peek(&mut self) -> Token {
575            self.nth(0)
576        }
577        /// Peek the `n`th token, not including whitespace and comments
578        fn nth(&mut self, n: usize) -> Token;
579        /// Consume the token and point to the next token
580        fn consume(&mut self);
581        fn error(&mut self, e: impl Into<String>);
582        fn warning(&mut self, e: impl Into<String>);
583
584        /// Consume the token if it has the right kind, otherwise report a syntax error.
585        /// Returns true if the token was consumed.
586        fn expect(&mut self, kind: SyntaxKind) -> bool {
587            if !self.test(kind) {
588                self.error(format!("Syntax error: expected {kind}"));
589                return false;
590            }
591            true
592        }
593
594        /// If the token if of this type, consume it and return true, otherwise return false
595        fn test(&mut self, kind: SyntaxKind) -> bool {
596            if self.nth(0).kind() != kind {
597                return false;
598            }
599            self.consume();
600            true
601        }
602
603        /// consume everything until reaching a token of this kind
604        fn until(&mut self, kind: SyntaxKind) {
605            let mut parens = 0;
606            let mut braces = 0;
607            let mut brackets = 0;
608            loop {
609                match self.nth(0).kind() {
610                    k if k == kind && parens == 0 && braces == 0 && brackets == 0 => break,
611                    SyntaxKind::Eof => break,
612                    SyntaxKind::LParent => parens += 1,
613                    SyntaxKind::LBrace => braces += 1,
614                    SyntaxKind::LBracket => brackets += 1,
615                    SyntaxKind::RParent if parens == 0 => break,
616                    SyntaxKind::RParent => parens -= 1,
617                    SyntaxKind::RBrace if braces == 0 => break,
618                    SyntaxKind::RBrace => braces -= 1,
619                    SyntaxKind::RBracket if brackets == 0 => break,
620                    SyntaxKind::RBracket => brackets -= 1,
621                    _ => {}
622                };
623                self.consume();
624            }
625            self.expect(kind);
626        }
627    }
628
629    /// A token to proof that start_node_impl and finish_node_impl are only
630    /// called from the Node implementation
631    ///
632    /// Since the constructor is private, it cannot be produced by anything else.
633    pub struct NodeToken(());
634    /// The return value of `DefaultParser::start_node`. This borrows the parser
635    /// and finishes the node on Drop
636    #[derive(derive_more::DerefMut)]
637    pub struct Node<'a, P: Parser>(&'a mut P);
638    impl<P: Parser> Drop for Node<'_, P> {
639        fn drop(&mut self) {
640            self.0.finish_node_impl(NodeToken(()));
641        }
642    }
643    impl<P: Parser> core::ops::Deref for Node<'_, P> {
644        type Target = P;
645        fn deref(&self) -> &Self::Target {
646            self.0
647        }
648    }
649}
650#[doc(inline)]
651pub use parser_trait::*;
652
653pub struct DefaultParser<'a> {
654    builder: rowan::GreenNodeBuilder<'static>,
655    /// tokens from the lexer
656    tokens: Vec<Token>,
657    /// points on the current token of the token list
658    cursor: usize,
659    diags: &'a mut BuildDiagnostics,
660    source_file: SourceFile,
661}
662
663impl<'a> DefaultParser<'a> {
664    fn from_tokens(tokens: Vec<Token>, diags: &'a mut BuildDiagnostics) -> Self {
665        Self {
666            builder: Default::default(),
667            tokens,
668            cursor: 0,
669            diags,
670            source_file: Default::default(),
671        }
672    }
673
674    /// Constructor that create a parser from the source code.
675    /// It creates the tokens by lexing the code
676    pub fn new(source: &str, diags: &'a mut BuildDiagnostics) -> Self {
677        Self::from_tokens(crate::lexer::lex(source), diags)
678    }
679
680    fn current_token(&self) -> Token {
681        self.tokens.get(self.cursor).cloned().unwrap_or_default()
682    }
683
684    /// Where a diagnostic reported at the current token points to
685    fn current_token_location(&self) -> crate::diagnostics::SourceLocation {
686        let token = self.current_token();
687        crate::diagnostics::SourceLocation {
688            source_file: Some(self.source_file.clone()),
689            span: crate::diagnostics::Span::new(token.offset, token.text.len()),
690        }
691    }
692
693    /// Consume all the whitespace
694    pub fn consume_ws(&mut self) {
695        while matches!(self.current_token().kind, SyntaxKind::Whitespace | SyntaxKind::Comment) {
696            self.consume()
697        }
698    }
699}
700
701impl Parser for DefaultParser<'_> {
702    fn start_node_impl(
703        &mut self,
704        kind: SyntaxKind,
705        checkpoint: Option<Self::Checkpoint>,
706        _: NodeToken,
707    ) {
708        if kind != SyntaxKind::Document {
709            self.consume_ws();
710        }
711        match checkpoint {
712            None => self.builder.start_node(kind.into()),
713            Some(cp) => self.builder.start_node_at(cp, kind.into()),
714        }
715    }
716
717    fn finish_node_impl(&mut self, _: NodeToken) {
718        self.builder.finish_node();
719    }
720
721    /// Peek the `n`th token starting from the cursor position, not including whitespace and comments
722    fn nth(&mut self, mut n: usize) -> Token {
723        self.consume_ws();
724        let mut c = self.cursor;
725        while n > 0 {
726            n -= 1;
727            c += 1;
728            while c < self.tokens.len()
729                && matches!(self.tokens[c].kind, SyntaxKind::Whitespace | SyntaxKind::Comment)
730            {
731                c += 1;
732            }
733        }
734        self.tokens.get(c).cloned().unwrap_or_default()
735    }
736
737    /// Adds the current token to the node builder and increments the cursor to point on the next token
738    fn consume(&mut self) {
739        let t = self.current_token();
740        self.builder.token(t.kind.into(), t.text.as_str());
741        if t.kind != SyntaxKind::Eof {
742            self.cursor += 1;
743        }
744    }
745
746    /// Reports an error at the current token location
747    fn error(&mut self, e: impl Into<String>) {
748        let location = self.current_token_location();
749        self.diags.push_error_with_span(e.into(), location);
750    }
751
752    /// Reports a warning at the current token location
753    fn warning(&mut self, e: impl Into<String>) {
754        let location = self.current_token_location();
755        self.diags.push_warning_with_span(e.into(), location);
756    }
757
758    type Checkpoint = rowan::Checkpoint;
759    fn checkpoint(&mut self) -> Self::Checkpoint {
760        self.builder.checkpoint()
761    }
762}
763
764#[derive(Clone, Copy, Debug, Eq, Ord, Hash, PartialEq, PartialOrd)]
765pub enum Language {}
766impl rowan::Language for Language {
767    type Kind = SyntaxKind;
768    fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind {
769        SyntaxKind::try_from(raw.0).unwrap()
770    }
771    fn kind_to_raw(kind: Self::Kind) -> rowan::SyntaxKind {
772        kind.into()
773    }
774}
775
776#[derive(Debug, Clone, derive_more::Deref)]
777pub struct SyntaxNode {
778    #[deref]
779    pub node: rowan::SyntaxNode<Language>,
780    pub source_file: SourceFile,
781}
782
783#[derive(Debug, Clone, derive_more::Deref)]
784pub struct SyntaxToken {
785    #[deref]
786    pub token: rowan::SyntaxToken<Language>,
787    pub source_file: SourceFile,
788}
789
790impl SyntaxToken {
791    pub fn parent(&self) -> SyntaxNode {
792        SyntaxNode { node: self.token.parent().unwrap(), source_file: self.source_file.clone() }
793    }
794    pub fn parent_ancestors(&self) -> impl Iterator<Item = SyntaxNode> + '_ {
795        self.token
796            .parent_ancestors()
797            .map(|node| SyntaxNode { node, source_file: self.source_file.clone() })
798    }
799    pub fn next_token(&self) -> Option<SyntaxToken> {
800        // Due to a bug (as of rowan 0.15.3), rowan::SyntaxToken::next_token doesn't work if a
801        // sibling don't have tokens.
802        // For example, if we have an expression like  `if (true) {}`  the
803        // ConditionalExpression has an empty Expression/CodeBlock  for the else part,
804        // and next_token doesn't go into that.
805        // So re-implement
806
807        let token = self
808            .token
809            .next_sibling_or_token()
810            .and_then(|e| match e {
811                rowan::NodeOrToken::Node(n) => n.first_token(),
812                rowan::NodeOrToken::Token(t) => Some(t),
813            })
814            .or_else(|| {
815                self.token.parent_ancestors().find_map(|it| it.next_sibling_or_token()).and_then(
816                    |e| match e {
817                        rowan::NodeOrToken::Node(n) => n.first_token(),
818                        rowan::NodeOrToken::Token(t) => Some(t),
819                    },
820                )
821            })?;
822        Some(SyntaxToken { token, source_file: self.source_file.clone() })
823    }
824    pub fn prev_token(&self) -> Option<SyntaxToken> {
825        let token = self.token.prev_token()?;
826        Some(SyntaxToken { token, source_file: self.source_file.clone() })
827    }
828    pub fn text(&self) -> &str {
829        self.token.text()
830    }
831}
832
833impl std::fmt::Display for SyntaxToken {
834    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
835        self.token.fmt(f)
836    }
837}
838
839impl SyntaxNode {
840    pub fn child_node(&self, kind: SyntaxKind) -> Option<SyntaxNode> {
841        self.node
842            .children()
843            .find(|n| n.kind() == kind)
844            .map(|node| SyntaxNode { node, source_file: self.source_file.clone() })
845    }
846    pub fn child_token(&self, kind: SyntaxKind) -> Option<SyntaxToken> {
847        self.node
848            .children_with_tokens()
849            .find(|n| n.kind() == kind)
850            .and_then(|x| x.into_token())
851            .map(|token| SyntaxToken { token, source_file: self.source_file.clone() })
852    }
853    pub fn child_text(&self, kind: SyntaxKind) -> Option<SmolStr> {
854        self.node
855            .children_with_tokens()
856            .find(|n| n.kind() == kind)
857            .and_then(|x| x.as_token().map(|x| x.text().into()))
858    }
859    pub fn descendants(&self) -> impl Iterator<Item = SyntaxNode> + use<> {
860        let source_file = self.source_file.clone();
861        self.node
862            .descendants()
863            .map(move |node| SyntaxNode { node, source_file: source_file.clone() })
864    }
865    pub fn kind(&self) -> SyntaxKind {
866        self.node.kind()
867    }
868    pub fn children(&self) -> impl Iterator<Item = SyntaxNode> + use<> {
869        let source_file = self.source_file.clone();
870        self.node.children().map(move |node| SyntaxNode { node, source_file: source_file.clone() })
871    }
872    pub fn children_with_tokens(&self) -> impl Iterator<Item = NodeOrToken> + use<> {
873        let source_file = self.source_file.clone();
874        self.node.children_with_tokens().map(move |token| match token {
875            rowan::NodeOrToken::Node(node) => {
876                SyntaxNode { node, source_file: source_file.clone() }.into()
877            }
878            rowan::NodeOrToken::Token(token) => {
879                SyntaxToken { token, source_file: source_file.clone() }.into()
880            }
881        })
882    }
883    pub fn text(&self) -> rowan::SyntaxText {
884        self.node.text()
885    }
886    pub fn parent(&self) -> Option<SyntaxNode> {
887        self.node.parent().map(|node| SyntaxNode { node, source_file: self.source_file.clone() })
888    }
889    pub fn first_token(&self) -> Option<SyntaxToken> {
890        self.node
891            .first_token()
892            .map(|token| SyntaxToken { token, source_file: self.source_file.clone() })
893    }
894    pub fn last_token(&self) -> Option<SyntaxToken> {
895        self.node
896            .last_token()
897            .map(|token| SyntaxToken { token, source_file: self.source_file.clone() })
898    }
899    pub fn token_at_offset(&self, offset: TextSize) -> rowan::TokenAtOffset<SyntaxToken> {
900        self.node
901            .token_at_offset(offset)
902            .map(|token| SyntaxToken { token, source_file: self.source_file.clone() })
903    }
904    pub fn first_child(&self) -> Option<SyntaxNode> {
905        self.node
906            .first_child()
907            .map(|node| SyntaxNode { node, source_file: self.source_file.clone() })
908    }
909    pub fn first_child_or_token(&self) -> Option<NodeOrToken> {
910        self.node.first_child_or_token().map(|n_o_t| match n_o_t {
911            rowan::NodeOrToken::Node(node) => {
912                NodeOrToken::Node(SyntaxNode { node, source_file: self.source_file.clone() })
913            }
914            rowan::NodeOrToken::Token(token) => {
915                NodeOrToken::Token(SyntaxToken { token, source_file: self.source_file.clone() })
916            }
917        })
918    }
919    pub fn next_sibling(&self) -> Option<SyntaxNode> {
920        self.node
921            .next_sibling()
922            .map(|node| SyntaxNode { node, source_file: self.source_file.clone() })
923    }
924}
925
926#[derive(Debug, Clone, derive_more::From)]
927pub enum NodeOrToken {
928    Node(SyntaxNode),
929    Token(SyntaxToken),
930}
931
932impl NodeOrToken {
933    pub fn kind(&self) -> SyntaxKind {
934        match self {
935            NodeOrToken::Node(n) => n.kind(),
936            NodeOrToken::Token(t) => t.kind(),
937        }
938    }
939
940    pub fn as_node(&self) -> Option<&SyntaxNode> {
941        match self {
942            NodeOrToken::Node(n) => Some(n),
943            NodeOrToken::Token(_) => None,
944        }
945    }
946
947    pub fn as_token(&self) -> Option<&SyntaxToken> {
948        match self {
949            NodeOrToken::Node(_) => None,
950            NodeOrToken::Token(t) => Some(t),
951        }
952    }
953
954    pub fn into_token(self) -> Option<SyntaxToken> {
955        match self {
956            NodeOrToken::Token(t) => Some(t),
957            _ => None,
958        }
959    }
960
961    pub fn into_node(self) -> Option<SyntaxNode> {
962        match self {
963            NodeOrToken::Node(n) => Some(n),
964            _ => None,
965        }
966    }
967
968    pub fn text_range(&self) -> TextRange {
969        match self {
970            NodeOrToken::Node(n) => n.text_range(),
971            NodeOrToken::Token(t) => t.text_range(),
972        }
973    }
974}
975
976impl Spanned for SyntaxNode {
977    fn span(&self) -> crate::diagnostics::Span {
978        let range = self.node.text_range();
979        crate::diagnostics::Span::new(range.start().into(), range.len().into())
980    }
981
982    fn source_file(&self) -> Option<&SourceFile> {
983        Some(&self.source_file)
984    }
985}
986
987impl Spanned for Option<SyntaxNode> {
988    fn span(&self) -> crate::diagnostics::Span {
989        self.as_ref().map(|n| n.span()).unwrap_or_default()
990    }
991
992    fn source_file(&self) -> Option<&SourceFile> {
993        self.as_ref().and_then(|n| n.source_file())
994    }
995}
996
997impl Spanned for SyntaxToken {
998    fn span(&self) -> crate::diagnostics::Span {
999        let range = self.token.text_range();
1000        crate::diagnostics::Span::new(range.start().into(), range.len().into())
1001    }
1002
1003    fn source_file(&self) -> Option<&SourceFile> {
1004        Some(&self.source_file)
1005    }
1006}
1007
1008impl Spanned for NodeOrToken {
1009    fn span(&self) -> crate::diagnostics::Span {
1010        match self {
1011            NodeOrToken::Node(n) => n.span(),
1012            NodeOrToken::Token(t) => t.span(),
1013        }
1014    }
1015
1016    fn source_file(&self) -> Option<&SourceFile> {
1017        match self {
1018            NodeOrToken::Node(n) => n.source_file(),
1019            NodeOrToken::Token(t) => t.source_file(),
1020        }
1021    }
1022}
1023
1024impl Spanned for Option<NodeOrToken> {
1025    fn span(&self) -> crate::diagnostics::Span {
1026        self.as_ref().map(|t| t.span()).unwrap_or_default()
1027    }
1028    fn source_file(&self) -> Option<&SourceFile> {
1029        self.as_ref().and_then(|t| t.source_file())
1030    }
1031}
1032
1033impl Spanned for Option<SyntaxToken> {
1034    fn span(&self) -> crate::diagnostics::Span {
1035        self.as_ref().map(|t| t.span()).unwrap_or_default()
1036    }
1037    fn source_file(&self) -> Option<&SourceFile> {
1038        self.as_ref().and_then(|t| t.source_file())
1039    }
1040}
1041
1042/// return the normalized identifier string of the first SyntaxKind::Identifier in this node
1043pub fn identifier_text(node: &SyntaxNode) -> Option<SmolStr> {
1044    node.child_text(SyntaxKind::Identifier).map(|x| normalize_identifier(&x))
1045}
1046
1047pub fn normalize_identifier(ident: &str) -> SmolStr {
1048    if is_identifier_normalized(ident) {
1049        // one bulk copy instead of the char-by-char builder below
1050        return SmolStr::new(ident);
1051    }
1052    let mut builder = smol_str::SmolStrBuilder::default();
1053    for (pos, c) in ident.chars().enumerate() {
1054        match (pos, c) {
1055            (0, '-') | (0, '_') => builder.push('_'),
1056            (_, '_') => builder.push('-'),
1057            (_, c) => builder.push(c),
1058        }
1059    }
1060    builder.finish()
1061}
1062
1063/// Returns true if [`normalize_identifier`] would return `ident` unchanged.
1064/// Lets callers skip the copy (and heap allocation for long identifiers).
1065pub fn is_identifier_normalized(ident: &str) -> bool {
1066    // '-' and '_' are ASCII, so a byte scan is UTF-8-safe
1067    let b = ident.as_bytes();
1068    b.first() != Some(&b'-') && !b[1.min(b.len())..].contains(&b'_')
1069}
1070
1071#[test]
1072fn test_normalize_identifier() {
1073    assert_eq!(normalize_identifier("true"), SmolStr::new("true"));
1074    assert_eq!(normalize_identifier("foo_bar"), SmolStr::new("foo-bar"));
1075    assert_eq!(normalize_identifier("-foo_bar"), SmolStr::new("_foo-bar"));
1076    assert_eq!(normalize_identifier("-foo-bar"), SmolStr::new("_foo-bar"));
1077    assert_eq!(normalize_identifier("foo_bar_"), SmolStr::new("foo-bar-"));
1078    assert_eq!(normalize_identifier("foo_bar-"), SmolStr::new("foo-bar-"));
1079    assert_eq!(normalize_identifier("_foo_bar_"), SmolStr::new("_foo-bar-"));
1080    assert_eq!(normalize_identifier("__1"), SmolStr::new("_-1"));
1081    assert_eq!(normalize_identifier("--1"), SmolStr::new("_-1"));
1082    assert_eq!(normalize_identifier("--1--"), SmolStr::new("_-1--"));
1083}
1084
1085#[test]
1086fn test_is_identifier_normalized() {
1087    for ident in
1088        ["true", "foo-bar", "foo_bar", "-foo", "_foo", "foo-bar-", "", "-", "_", "ä_ö", "ä-ö"]
1089    {
1090        assert_eq!(
1091            is_identifier_normalized(ident),
1092            normalize_identifier(ident) == ident,
1093            "{ident:?}"
1094        );
1095    }
1096}
1097
1098// Actual parser
1099pub fn parse(
1100    source: String,
1101    path: Option<&std::path::Path>,
1102    build_diagnostics: &mut BuildDiagnostics,
1103) -> SyntaxNode {
1104    let mut p = DefaultParser::new(&source, build_diagnostics);
1105    p.source_file = std::sync::Arc::new(crate::diagnostics::SourceFileInner::new(
1106        path.map(crate::pathutils::clean_path).unwrap_or_default(),
1107        source,
1108    ));
1109    document::parse_document(&mut p);
1110    SyntaxNode {
1111        node: rowan::SyntaxNode::new_root(p.builder.finish()),
1112        source_file: p.source_file.clone(),
1113    }
1114}
1115
1116pub fn parse_file<P: AsRef<std::path::Path>>(
1117    path: P,
1118    build_diagnostics: &mut BuildDiagnostics,
1119) -> Option<SyntaxNode> {
1120    let path = crate::pathutils::clean_path(path.as_ref());
1121    let source = crate::diagnostics::load_from_path(&path)
1122        .map_err(|d| build_diagnostics.push_internal_error(d))
1123        .ok()?;
1124    Some(parse(source, Some(path.as_ref()), build_diagnostics))
1125}
1126
1127pub fn parse_tokens(
1128    tokens: Vec<Token>,
1129    source_file: SourceFile,
1130    diags: &mut BuildDiagnostics,
1131) -> SyntaxNode {
1132    let mut p = DefaultParser::from_tokens(tokens, diags);
1133    document::parse_document(&mut p);
1134    SyntaxNode { node: rowan::SyntaxNode::new_root(p.builder.finish()), source_file }
1135}