mirror of
				https://github.com/slint-ui/slint.git
				synced 2025-11-04 05:34:37 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1056 lines
		
	
	
	
		
			37 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			1056 lines
		
	
	
	
		
			37 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
// Copyright © SixtyFPS GmbH <info@slint.dev>
 | 
						|
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
 | 
						|
 | 
						|
/*! The Slint Language Parser
 | 
						|
 | 
						|
This module is responsible to parse a string onto a syntax tree.
 | 
						|
 | 
						|
The core of it is the `DefaultParser` class that holds a list of token and
 | 
						|
generates a `rowan::GreenNode`
 | 
						|
 | 
						|
This module has different sub modules with the actual parser functions
 | 
						|
 | 
						|
*/
 | 
						|
 | 
						|
use crate::diagnostics::{BuildDiagnostics, SourceFile, Spanned};
 | 
						|
use smol_str::{SmolStr, StrExt};
 | 
						|
use std::fmt::Display;
 | 
						|
 | 
						|
mod document;
 | 
						|
mod element;
 | 
						|
mod expressions;
 | 
						|
mod statements;
 | 
						|
mod r#type;
 | 
						|
 | 
						|
/// Each parser submodule would simply do `use super::prelude::*` to import typically used items
 | 
						|
mod prelude {
 | 
						|
    #[cfg(test)]
 | 
						|
    pub use super::DefaultParser;
 | 
						|
    #[cfg(test)]
 | 
						|
    pub use super::{syntax_nodes, SyntaxNode, SyntaxNodeVerify};
 | 
						|
    pub use super::{Parser, SyntaxKind};
 | 
						|
    #[cfg(test)]
 | 
						|
    pub use i_slint_parser_test_macro::parser_test;
 | 
						|
}
 | 
						|
 | 
						|
#[cfg(test)]
 | 
						|
pub trait SyntaxNodeVerify {
 | 
						|
    /// The SyntaxKind corresponding to this type
 | 
						|
    const KIND: SyntaxKind;
 | 
						|
    /// Asserts that the node is of the given SyntaxKind and that it has the expected children
 | 
						|
    /// Panic if this is not the case
 | 
						|
    fn verify(node: SyntaxNode) {
 | 
						|
        assert_eq!(node.kind(), Self::KIND)
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
pub use rowan::{TextRange, TextSize};
 | 
						|
 | 
						|
/// Check that a node has the assumed children
 | 
						|
#[cfg(test)]
 | 
						|
macro_rules! verify_node {
 | 
						|
    // Some combination of children
 | 
						|
    ($node:ident, [ $($t1:tt $($t2:ident)?),* ]) => {
 | 
						|
        // Check that every children is there
 | 
						|
        $(verify_node!(@check_has_children $node, $t1 $($t2)* );)*
 | 
						|
 | 
						|
        // check that there are not too many nodes
 | 
						|
        for c in $node.children() {
 | 
						|
            assert!(
 | 
						|
                false $(|| c.kind() == verify_node!(@extract_kind $t1 $($t2)*))*,
 | 
						|
                "Node is none of [{}]\n{:?}", stringify!($($t1 $($t2)*),*) ,c);
 | 
						|
        }
 | 
						|
 | 
						|
        // recurse
 | 
						|
        $(
 | 
						|
            for _c in $node.children().filter(|n| n.kind() == verify_node!(@extract_kind $t1 $($t2)*)) {
 | 
						|
                <verify_node!(@extract_type $t1 $($t2)*)>::verify(_c)
 | 
						|
            }
 | 
						|
        )*
 | 
						|
    };
 | 
						|
 | 
						|
    // Any number of this kind.
 | 
						|
    (@check_has_children $node:ident, * $kind:ident) => {};
 | 
						|
    // 1 or 0
 | 
						|
    (@check_has_children $node:ident, ? $kind:ident) => {
 | 
						|
        let count = $node.children_with_tokens().filter(|n| n.kind() == SyntaxKind::$kind).count();
 | 
						|
        assert!(count <= 1, "Expecting one or zero sub-node of type {}, found {}\n{:?}", stringify!($kind), count, $node);
 | 
						|
    };
 | 
						|
    // Exactly one
 | 
						|
    (@check_has_children $node:ident, $kind:ident) => {
 | 
						|
        let count = $node.children_with_tokens().filter(|n| n.kind() == SyntaxKind::$kind).count();
 | 
						|
        assert_eq!(count, 1, "Expecting exactly one sub-node of type {}\n{:?}", stringify!($kind), $node);
 | 
						|
    };
 | 
						|
    // Exact number
 | 
						|
    (@check_has_children $node:ident, $count:literal $kind:ident) => {
 | 
						|
        let count = $node.children_with_tokens().filter(|n| n.kind() == SyntaxKind::$kind).count();
 | 
						|
        assert_eq!(count, $count, "Expecting {} sub-node of type {}, found {}\n{:?}", $count, stringify!($kind), count, $node);
 | 
						|
    };
 | 
						|
 | 
						|
    (@extract_kind * $kind:ident) => {SyntaxKind::$kind};
 | 
						|
    (@extract_kind ? $kind:ident) => {SyntaxKind::$kind};
 | 
						|
    (@extract_kind $count:literal $kind:ident) => {SyntaxKind::$kind};
 | 
						|
    (@extract_kind $kind:ident) => {SyntaxKind::$kind};
 | 
						|
 | 
						|
    (@extract_type * $kind:ident) => {$crate::parser::syntax_nodes::$kind};
 | 
						|
    (@extract_type ? $kind:ident) => {$crate::parser::syntax_nodes::$kind};
 | 
						|
    (@extract_type $count:literal $kind:ident) => {$crate::parser::syntax_nodes::$kind};
 | 
						|
    (@extract_type $kind:ident) => {$crate::parser::syntax_nodes::$kind};
 | 
						|
}
 | 
						|
 | 
						|
macro_rules! node_accessors {
 | 
						|
    // Some combination of children
 | 
						|
    ([ $($t1:tt $($t2:ident)?),* ]) => {
 | 
						|
        $(node_accessors!{@ $t1 $($t2)*} )*
 | 
						|
    };
 | 
						|
 | 
						|
    (@ * $kind:ident) => {
 | 
						|
        #[allow(non_snake_case)]
 | 
						|
        pub fn $kind(&self) -> impl Iterator<Item = $kind> {
 | 
						|
            self.0.children().filter(|n| n.kind() == SyntaxKind::$kind).map(Into::into)
 | 
						|
        }
 | 
						|
    };
 | 
						|
    (@ ? $kind:ident) => {
 | 
						|
        #[allow(non_snake_case)]
 | 
						|
        pub fn $kind(&self) -> Option<$kind> {
 | 
						|
            self.0.child_node(SyntaxKind::$kind).map(Into::into)
 | 
						|
        }
 | 
						|
    };
 | 
						|
    (@ 2 $kind:ident) => {
 | 
						|
        #[allow(non_snake_case)]
 | 
						|
        #[track_caller]
 | 
						|
        pub fn $kind(&self) -> ($kind, $kind) {
 | 
						|
            let mut it = self.0.children().filter(|n| n.kind() == SyntaxKind::$kind);
 | 
						|
            let a = it.next().expect(stringify!(Missing first $kind));
 | 
						|
            let b = it.next().expect(stringify!(Missing second $kind));
 | 
						|
            debug_assert!(it.next().is_none(), stringify!(More $kind than expected));
 | 
						|
            (a.into(), b.into())
 | 
						|
        }
 | 
						|
    };
 | 
						|
    (@ 3 $kind:ident) => {
 | 
						|
        #[allow(non_snake_case)]
 | 
						|
        #[track_caller]
 | 
						|
        pub fn $kind(&self) -> ($kind, $kind, $kind) {
 | 
						|
            let mut it = self.0.children().filter(|n| n.kind() == SyntaxKind::$kind);
 | 
						|
            let a = it.next().expect(stringify!(Missing first $kind));
 | 
						|
            let b = it.next().expect(stringify!(Missing second $kind));
 | 
						|
            let c = it.next().expect(stringify!(Missing third $kind));
 | 
						|
            debug_assert!(it.next().is_none(), stringify!(More $kind than expected));
 | 
						|
            (a.into(), b.into(), c.into())
 | 
						|
        }
 | 
						|
    };
 | 
						|
    (@ $kind:ident) => {
 | 
						|
        #[allow(non_snake_case)]
 | 
						|
        #[track_caller]
 | 
						|
        pub fn $kind(&self) -> $kind {
 | 
						|
            self.0.child_node(SyntaxKind::$kind).expect(stringify!(Missing $kind)).into()
 | 
						|
        }
 | 
						|
    };
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/// This macro is invoked once, to declare all the token and syntax kind.
 | 
						|
/// The purpose of this macro is to declare the token with its regexp at the same place,
 | 
						|
/// and the nodes with their contents.
 | 
						|
///
 | 
						|
/// This is split into two group: first the tokens, then the nodes.
 | 
						|
///
 | 
						|
/// # Tokens
 | 
						|
///
 | 
						|
/// Given as `$token:ident -> $rule:expr`. The rule parameter can be either a string literal or
 | 
						|
/// a lexer function. The order of tokens is important because the rules will be run in that order
 | 
						|
/// and the first one matching will be chosen.
 | 
						|
///
 | 
						|
/// # Nodes
 | 
						|
///
 | 
						|
/// Given as `$(#[$attr:meta])* $nodekind:ident -> [$($children:tt),*] `.
 | 
						|
/// Where `children` is a list of sub-nodes (not including tokens).
 | 
						|
/// This will allow to self-document and create the structure from the [`syntax_nodes`] module.
 | 
						|
/// The children can be prefixed with the following symbol:
 | 
						|
///
 | 
						|
/// - nothing: The node occurs once and exactly once, the generated accessor returns the node itself
 | 
						|
/// - `+`: the node occurs one or several times, the generated accessor returns an `Iterator`
 | 
						|
/// - `*`: the node occurs zero or several times, the generated accessor returns an `Iterator`
 | 
						|
/// - `?`: the node occurs once or zero times, the generated accessor returns an `Option`
 | 
						|
/// - `2` or `3`: the node occurs exactly two or three times, the generated accessor returns a tuple
 | 
						|
///
 | 
						|
/// Note: the parser must generate the right amount of sub nodes, even if there is a parse error.
 | 
						|
///
 | 
						|
/// ## The [`syntax_nodes`] module
 | 
						|
///
 | 
						|
/// Creates one struct for every node with the given accessor.
 | 
						|
/// The struct can be converted from and to the node.
 | 
						|
macro_rules! declare_syntax {
 | 
						|
    ({
 | 
						|
        $($token:ident -> $rule:expr ,)*
 | 
						|
     }
 | 
						|
     {
 | 
						|
        $( $(#[$attr:meta])*  $nodekind:ident -> $children:tt ,)*
 | 
						|
    })
 | 
						|
    => {
 | 
						|
        #[repr(u16)]
 | 
						|
        #[derive(Debug, Copy, Clone, Eq, PartialEq, num_enum::IntoPrimitive, num_enum::TryFromPrimitive, Hash, Ord, PartialOrd)]
 | 
						|
        pub enum SyntaxKind {
 | 
						|
            Error,
 | 
						|
            Eof,
 | 
						|
 | 
						|
            // Tokens:
 | 
						|
            $(
 | 
						|
                /// Token
 | 
						|
                $token,
 | 
						|
            )*
 | 
						|
 | 
						|
            // Nodes:
 | 
						|
            $(
 | 
						|
                $(#[$attr])*
 | 
						|
                $nodekind,
 | 
						|
            )*
 | 
						|
        }
 | 
						|
 | 
						|
        impl Display for SyntaxKind {
 | 
						|
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
						|
                match self {
 | 
						|
                    $(Self::$token => {
 | 
						|
                        if let Some(character) = <dyn std::any::Any>::downcast_ref::<&str>(& $rule) {
 | 
						|
                            return write!(f, "'{}'", character)
 | 
						|
                        }
 | 
						|
                    })*
 | 
						|
                    _ => ()
 | 
						|
                }
 | 
						|
                write!(f, "{:?}", self)
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        /// Returns a pair of the matched token type at the beginning of `text`, and its size
 | 
						|
        pub fn lex_next_token(text : &str, state: &mut crate::lexer::LexState) -> Option<(usize, SyntaxKind)> {
 | 
						|
            use crate::lexer::LexingRule;
 | 
						|
            $(
 | 
						|
                let len = ($rule).lex(text, state);
 | 
						|
                if len > 0 {
 | 
						|
                    return Some((len, SyntaxKind::$token));
 | 
						|
                }
 | 
						|
            )*
 | 
						|
            None
 | 
						|
        }
 | 
						|
 | 
						|
        pub mod syntax_nodes {
 | 
						|
            use super::*;
 | 
						|
            $(
 | 
						|
                #[derive(Debug, Clone, derive_more::Deref, derive_more::Into)]
 | 
						|
                pub struct $nodekind(SyntaxNode);
 | 
						|
                #[cfg(test)]
 | 
						|
                impl SyntaxNodeVerify for $nodekind {
 | 
						|
                    const KIND: SyntaxKind = SyntaxKind::$nodekind;
 | 
						|
                    #[track_caller]
 | 
						|
                    fn verify(node: SyntaxNode) {
 | 
						|
                        assert_eq!(node.kind(), Self::KIND);
 | 
						|
                        verify_node!(node, $children);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                impl $nodekind {
 | 
						|
                    node_accessors!{$children}
 | 
						|
 | 
						|
                    /// Create a new node from a SyntaxNode, if the SyntaxNode is of the correct kind
 | 
						|
                    pub fn new(node: SyntaxNode) -> Option<Self> {
 | 
						|
                        (node.kind() == SyntaxKind::$nodekind).then(|| Self(node))
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                impl From<SyntaxNode> for $nodekind {
 | 
						|
                    #[track_caller]
 | 
						|
                    fn from(node: SyntaxNode) -> Self {
 | 
						|
                        assert_eq!(node.kind(), SyntaxKind::$nodekind);
 | 
						|
                        Self(node)
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                impl Spanned for $nodekind {
 | 
						|
                    fn span(&self) -> crate::diagnostics::Span {
 | 
						|
                        self.0.span()
 | 
						|
                    }
 | 
						|
 | 
						|
                    fn source_file(&self) -> Option<&SourceFile> {
 | 
						|
                        self.0.source_file()
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            )*
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
declare_syntax! {
 | 
						|
    // Tokens.
 | 
						|
    // WARNING: when changing this, do not forget to update the tokenizer in the slint-rs-macro crate!
 | 
						|
    // The order of token is important because the rules will be run in that order
 | 
						|
    // and the first one matching will be chosen.
 | 
						|
    {
 | 
						|
        Whitespace -> &crate::lexer::lex_whitespace,
 | 
						|
        Comment -> &crate::lexer::lex_comment,
 | 
						|
        StringLiteral -> &crate::lexer::lex_string,
 | 
						|
        NumberLiteral -> &crate::lexer::lex_number,
 | 
						|
        ColorLiteral -> &crate::lexer::lex_color,
 | 
						|
        Identifier -> &crate::lexer::lex_identifier,
 | 
						|
        DoubleArrow -> "<=>",
 | 
						|
        PlusEqual -> "+=",
 | 
						|
        MinusEqual -> "-=",
 | 
						|
        StarEqual -> "*=",
 | 
						|
        DivEqual -> "/=",
 | 
						|
        LessEqual -> "<=",
 | 
						|
        GreaterEqual -> ">=",
 | 
						|
        EqualEqual -> "==",
 | 
						|
        NotEqual -> "!=",
 | 
						|
        ColonEqual -> ":=",
 | 
						|
        FatArrow -> "=>",
 | 
						|
        Arrow -> "->",
 | 
						|
        OrOr -> "||",
 | 
						|
        AndAnd -> "&&",
 | 
						|
        LBrace -> "{",
 | 
						|
        RBrace -> "}",
 | 
						|
        LParent -> "(",
 | 
						|
        RParent -> ")",
 | 
						|
        LAngle -> "<",
 | 
						|
        RAngle -> ">",
 | 
						|
        LBracket -> "[",
 | 
						|
        RBracket -> "]",
 | 
						|
        Plus -> "+",
 | 
						|
        Minus -> "-",
 | 
						|
        Star -> "*",
 | 
						|
        Div -> "/",
 | 
						|
        Equal -> "=",
 | 
						|
        Colon -> ":",
 | 
						|
        Comma -> ",",
 | 
						|
        Semicolon -> ";",
 | 
						|
        Bang -> "!",
 | 
						|
        Dot -> ".",
 | 
						|
        Question -> "?",
 | 
						|
        Dollar -> "$",
 | 
						|
        At -> "@",
 | 
						|
        Pipe -> "|",
 | 
						|
        Percent -> "%",
 | 
						|
    }
 | 
						|
    // syntax kind
 | 
						|
    {
 | 
						|
        Document -> [ *Component, *ExportsList, *ImportSpecifier, *StructDeclaration, *EnumDeclaration ],
 | 
						|
        /// `DeclaredIdentifier := Element { ... }`
 | 
						|
        Component -> [ DeclaredIdentifier, Element ],
 | 
						|
        /// `id := Element { ... }`
 | 
						|
        SubElement -> [ Element ],
 | 
						|
        Element -> [ ?QualifiedName, *PropertyDeclaration, *Binding, *CallbackConnection,
 | 
						|
                     *CallbackDeclaration, *ConditionalElement, *Function, *SubElement,
 | 
						|
                     *RepeatedElement, *PropertyAnimation, *PropertyChangedCallback,
 | 
						|
                     *TwoWayBinding, *States, *Transitions, ?ChildrenPlaceholder ],
 | 
						|
        RepeatedElement -> [ ?DeclaredIdentifier, ?RepeatedIndex, Expression , SubElement],
 | 
						|
        RepeatedIndex -> [],
 | 
						|
        ConditionalElement -> [ Expression , SubElement],
 | 
						|
        CallbackDeclaration -> [ DeclaredIdentifier, *CallbackDeclarationParameter, ?ReturnType, ?TwoWayBinding ],
 | 
						|
        // `foo: type` or just `type`
 | 
						|
        CallbackDeclarationParameter -> [ ?DeclaredIdentifier, Type],
 | 
						|
        Function -> [DeclaredIdentifier, *ArgumentDeclaration, ?ReturnType, CodeBlock ],
 | 
						|
        ArgumentDeclaration -> [DeclaredIdentifier, Type],
 | 
						|
        /// `-> type`  (but without the ->)
 | 
						|
        ReturnType -> [Type],
 | 
						|
        CallbackConnection -> [ *DeclaredIdentifier,  CodeBlock ],
 | 
						|
        /// Declaration of a property.
 | 
						|
        PropertyDeclaration-> [ ?Type , DeclaredIdentifier, ?BindingExpression, ?TwoWayBinding ],
 | 
						|
        /// QualifiedName are the properties name
 | 
						|
        PropertyAnimation-> [ *QualifiedName, *Binding ],
 | 
						|
        /// `changed xxx => {...}`  where `xxx` is the DeclaredIdentifier
 | 
						|
        PropertyChangedCallback-> [ DeclaredIdentifier, CodeBlock ],
 | 
						|
        /// wraps Identifiers, like `Rectangle` or `SomeModule.SomeType`
 | 
						|
        QualifiedName-> [],
 | 
						|
        /// Wraps single identifier (to disambiguate when there are other identifier in the production)
 | 
						|
        DeclaredIdentifier -> [],
 | 
						|
        ChildrenPlaceholder -> [],
 | 
						|
        Binding-> [ BindingExpression ],
 | 
						|
        /// `xxx <=> something`
 | 
						|
        TwoWayBinding -> [ Expression ],
 | 
						|
        /// the right-hand-side of a binding
 | 
						|
        // Fixme: the test should be a or
 | 
						|
        BindingExpression-> [ ?CodeBlock, ?Expression ],
 | 
						|
        CodeBlock-> [ *Expression, *ReturnStatement ],
 | 
						|
        ReturnStatement -> [ ?Expression ],
 | 
						|
        // FIXME: the test should test that as alternative rather than several of them (but it can also be a literal)
 | 
						|
        Expression-> [ ?Expression, ?FunctionCallExpression, ?IndexExpression, ?SelfAssignment,
 | 
						|
                       ?ConditionalExpression, ?QualifiedName, ?BinaryExpression, ?Array, ?ObjectLiteral,
 | 
						|
                       ?UnaryOpExpression, ?CodeBlock, ?StringTemplate, ?AtImageUrl, ?AtGradient, ?AtTr,
 | 
						|
                       ?MemberAccess ],
 | 
						|
        /// Concatenate the Expressions to make a string (usually expended from a template string)
 | 
						|
        StringTemplate -> [*Expression],
 | 
						|
        /// `@image-url("foo.png")`
 | 
						|
        AtImageUrl -> [],
 | 
						|
        /// `@linear-gradient(...)` or `@radial-gradient(...)`
 | 
						|
        AtGradient -> [*Expression],
 | 
						|
        /// `@tr("foo", ...)`  // the string is a StringLiteral
 | 
						|
        AtTr -> [?TrContext, ?TrPlural, *Expression],
 | 
						|
        /// `"foo" =>`  in a `AtTr` node
 | 
						|
        TrContext -> [],
 | 
						|
        /// `| "foo" % n`  in a `AtTr` node
 | 
						|
        TrPlural -> [Expression],
 | 
						|
        /// expression()
 | 
						|
        FunctionCallExpression -> [*Expression],
 | 
						|
        /// `expression[index]`
 | 
						|
        IndexExpression -> [2 Expression],
 | 
						|
        /// `expression += expression`
 | 
						|
        SelfAssignment -> [2 Expression],
 | 
						|
        /// `condition ? first : second`
 | 
						|
        ConditionalExpression -> [3 Expression],
 | 
						|
        /// `expr + expr`
 | 
						|
        BinaryExpression -> [2 Expression],
 | 
						|
        /// `- expr`
 | 
						|
        UnaryOpExpression -> [Expression],
 | 
						|
        /// `(foo).bar`, where `foo` is the base expression, and `bar` is a Identifier.
 | 
						|
        MemberAccess -> [Expression],
 | 
						|
        /// `[ ... ]`
 | 
						|
        Array -> [ *Expression ],
 | 
						|
        /// `{ foo: bar }`
 | 
						|
        ObjectLiteral -> [ *ObjectMember ],
 | 
						|
        /// `foo: bar` inside an ObjectLiteral
 | 
						|
        ObjectMember -> [ Expression ],
 | 
						|
        /// `states: [...]`
 | 
						|
        States -> [*State],
 | 
						|
        /// The DeclaredIdentifier is the state name. The Expression, if any, is the condition.
 | 
						|
        State -> [DeclaredIdentifier, ?Expression, *StatePropertyChange, *Transition],
 | 
						|
        /// binding within a state
 | 
						|
        StatePropertyChange -> [ QualifiedName, BindingExpression ],
 | 
						|
        /// `transitions: [...]`
 | 
						|
        Transitions -> [*Transition],
 | 
						|
        /// There is an identifier "in" or "out", the DeclaredIdentifier is the state name
 | 
						|
        Transition -> [?DeclaredIdentifier, *PropertyAnimation],
 | 
						|
        /// Export a set of declared components by name
 | 
						|
        ExportsList -> [ *ExportSpecifier, ?Component, *StructDeclaration, ?ExportModule, *EnumDeclaration ],
 | 
						|
        /// Declare the first identifier to be exported, either under its name or instead
 | 
						|
        /// under the name of the second identifier.
 | 
						|
        ExportSpecifier -> [ ExportIdentifier, ?ExportName ],
 | 
						|
        ExportIdentifier -> [],
 | 
						|
        ExportName -> [],
 | 
						|
        /// `export ... from "foo"`. The import uri is stored as string literal.
 | 
						|
        ExportModule -> [],
 | 
						|
        /// import { foo, bar, baz } from "blah"; The import uri is stored as string literal.
 | 
						|
        ImportSpecifier -> [ ?ImportIdentifierList ],
 | 
						|
        ImportIdentifierList -> [ *ImportIdentifier ],
 | 
						|
        /// { foo as bar } or just { foo }
 | 
						|
        ImportIdentifier -> [ ExternalName, ?InternalName ],
 | 
						|
        ExternalName -> [],
 | 
						|
        InternalName -> [],
 | 
						|
        /// The representation of a type
 | 
						|
        Type -> [ ?QualifiedName, ?ObjectType, ?ArrayType ],
 | 
						|
        /// `{foo: string, bar: string} `
 | 
						|
        ObjectType ->[ *ObjectTypeMember ],
 | 
						|
        /// `foo: type` inside an ObjectType
 | 
						|
        ObjectTypeMember -> [ Type ],
 | 
						|
        /// `[ type ]`
 | 
						|
        ArrayType -> [ Type ],
 | 
						|
        /// `struct Foo { ... }`
 | 
						|
        StructDeclaration -> [DeclaredIdentifier, ObjectType, ?AtRustAttr],
 | 
						|
        /// `enum Foo { bli, bla, blu }`
 | 
						|
        EnumDeclaration -> [DeclaredIdentifier, *EnumValue, ?AtRustAttr],
 | 
						|
        /// The value is a Identifier
 | 
						|
        EnumValue -> [],
 | 
						|
        /// `@rust-attr(...)`
 | 
						|
        AtRustAttr -> [],
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl From<SyntaxKind> for rowan::SyntaxKind {
 | 
						|
    fn from(v: SyntaxKind) -> Self {
 | 
						|
        rowan::SyntaxKind(v.into())
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Clone, Debug)]
 | 
						|
pub struct Token {
 | 
						|
    pub kind: SyntaxKind,
 | 
						|
    pub text: SmolStr,
 | 
						|
    pub offset: usize,
 | 
						|
    #[cfg(feature = "proc_macro_span")]
 | 
						|
    pub span: Option<proc_macro::Span>,
 | 
						|
}
 | 
						|
 | 
						|
impl Default for Token {
 | 
						|
    fn default() -> Self {
 | 
						|
        Token {
 | 
						|
            kind: SyntaxKind::Eof,
 | 
						|
            text: Default::default(),
 | 
						|
            offset: 0,
 | 
						|
            #[cfg(feature = "proc_macro_span")]
 | 
						|
            span: None,
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl Token {
 | 
						|
    pub fn as_str(&self) -> &str {
 | 
						|
        self.text.as_str()
 | 
						|
    }
 | 
						|
 | 
						|
    pub fn kind(&self) -> SyntaxKind {
 | 
						|
        self.kind
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
mod parser_trait {
 | 
						|
    //! module allowing to keep implementation details of the node private
 | 
						|
    use super::*;
 | 
						|
 | 
						|
    pub trait Parser: Sized {
 | 
						|
        type Checkpoint: Clone;
 | 
						|
 | 
						|
        /// Enter a new node.  The node is going to be finished when
 | 
						|
        /// The return value of this function is dropped
 | 
						|
        ///
 | 
						|
        /// (do not re-implement this function, re-implement
 | 
						|
        /// start_node_impl and finish_node_impl)
 | 
						|
        #[must_use = "The node will be finished when it is dropped"]
 | 
						|
        fn start_node(&mut self, kind: SyntaxKind) -> Node<Self> {
 | 
						|
            self.start_node_impl(kind, None, NodeToken(()));
 | 
						|
            Node(self)
 | 
						|
        }
 | 
						|
        #[must_use = "use start_node_at to use this checkpoint"]
 | 
						|
        fn checkpoint(&mut self) -> Self::Checkpoint;
 | 
						|
        #[must_use = "The node will be finished when it is dropped"]
 | 
						|
        fn start_node_at(
 | 
						|
            &mut self,
 | 
						|
            checkpoint: impl Into<Option<Self::Checkpoint>>,
 | 
						|
            kind: SyntaxKind,
 | 
						|
        ) -> Node<Self> {
 | 
						|
            self.start_node_impl(kind, checkpoint.into(), NodeToken(()));
 | 
						|
            Node(self)
 | 
						|
        }
 | 
						|
 | 
						|
        /// Can only be called by Node::drop
 | 
						|
        fn finish_node_impl(&mut self, token: NodeToken);
 | 
						|
        /// Can only be called by Self::start_node
 | 
						|
        fn start_node_impl(
 | 
						|
            &mut self,
 | 
						|
            kind: SyntaxKind,
 | 
						|
            checkpoint: Option<Self::Checkpoint>,
 | 
						|
            token: NodeToken,
 | 
						|
        );
 | 
						|
 | 
						|
        /// Same as nth(0)
 | 
						|
        fn peek(&mut self) -> Token {
 | 
						|
            self.nth(0)
 | 
						|
        }
 | 
						|
        /// Peek the `n`th token, not including whitespace and comments
 | 
						|
        fn nth(&mut self, n: usize) -> Token;
 | 
						|
        fn consume(&mut self);
 | 
						|
        fn error(&mut self, e: impl Into<String>);
 | 
						|
        fn warning(&mut self, e: impl Into<String>);
 | 
						|
 | 
						|
        /// Consume the token if it has the right kind, otherwise report a syntax error.
 | 
						|
        /// Returns true if the token was consumed.
 | 
						|
        fn expect(&mut self, kind: SyntaxKind) -> bool {
 | 
						|
            if !self.test(kind) {
 | 
						|
                self.error(format!("Syntax error: expected {}", kind));
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
            true
 | 
						|
        }
 | 
						|
 | 
						|
        /// If the token if of this type, consume it and return true, otherwise return false
 | 
						|
        fn test(&mut self, kind: SyntaxKind) -> bool {
 | 
						|
            if self.nth(0).kind() != kind {
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
            self.consume();
 | 
						|
            true
 | 
						|
        }
 | 
						|
 | 
						|
        /// consume everything until reaching a token of this kind
 | 
						|
        fn until(&mut self, kind: SyntaxKind) {
 | 
						|
            let mut parens = 0;
 | 
						|
            let mut braces = 0;
 | 
						|
            let mut brackets = 0;
 | 
						|
            loop {
 | 
						|
                match self.nth(0).kind() {
 | 
						|
                    k if k == kind && parens == 0 && braces == 0 && brackets == 0 => break,
 | 
						|
                    SyntaxKind::Eof => break,
 | 
						|
                    SyntaxKind::LParent => parens += 1,
 | 
						|
                    SyntaxKind::LBrace => braces += 1,
 | 
						|
                    SyntaxKind::LBracket => brackets += 1,
 | 
						|
                    SyntaxKind::RParent if parens == 0 => break,
 | 
						|
                    SyntaxKind::RParent => parens -= 1,
 | 
						|
                    SyntaxKind::RBrace if braces == 0 => break,
 | 
						|
                    SyntaxKind::RBrace => braces -= 1,
 | 
						|
                    SyntaxKind::RBracket if brackets == 0 => break,
 | 
						|
                    SyntaxKind::RBracket => brackets -= 1,
 | 
						|
                    _ => {}
 | 
						|
                };
 | 
						|
                self.consume();
 | 
						|
            }
 | 
						|
            self.expect(kind);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /// A token to proof that start_node_impl and finish_node_impl are only
 | 
						|
    /// called from the Node implementation
 | 
						|
    ///
 | 
						|
    /// Since the constructor is private, it cannot be produced by anything else.
 | 
						|
    pub struct NodeToken(());
 | 
						|
    /// The return value of `DefaultParser::start_node`. This borrows the parser
 | 
						|
    /// and finishes the node on Drop
 | 
						|
    #[derive(derive_more::DerefMut)]
 | 
						|
    pub struct Node<'a, P: Parser>(&'a mut P);
 | 
						|
    impl<'a, P: Parser> Drop for Node<'a, P> {
 | 
						|
        fn drop(&mut self) {
 | 
						|
            self.0.finish_node_impl(NodeToken(()));
 | 
						|
        }
 | 
						|
    }
 | 
						|
    impl<'a, P: Parser> core::ops::Deref for Node<'a, P> {
 | 
						|
        type Target = P;
 | 
						|
        fn deref(&self) -> &Self::Target {
 | 
						|
            self.0
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
#[doc(inline)]
 | 
						|
pub use parser_trait::*;
 | 
						|
 | 
						|
pub struct DefaultParser<'a> {
 | 
						|
    builder: rowan::GreenNodeBuilder<'static>,
 | 
						|
    tokens: Vec<Token>,
 | 
						|
    cursor: usize,
 | 
						|
    diags: &'a mut BuildDiagnostics,
 | 
						|
    source_file: SourceFile,
 | 
						|
}
 | 
						|
 | 
						|
impl<'a> DefaultParser<'a> {
 | 
						|
    fn from_tokens(tokens: Vec<Token>, diags: &'a mut BuildDiagnostics) -> Self {
 | 
						|
        Self {
 | 
						|
            builder: Default::default(),
 | 
						|
            tokens,
 | 
						|
            cursor: 0,
 | 
						|
            diags,
 | 
						|
            source_file: Default::default(),
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /// Constructor that create a parser from the source code
 | 
						|
    pub fn new(source: &str, diags: &'a mut BuildDiagnostics) -> Self {
 | 
						|
        Self::from_tokens(crate::lexer::lex(source), diags)
 | 
						|
    }
 | 
						|
 | 
						|
    fn current_token(&self) -> Token {
 | 
						|
        self.tokens.get(self.cursor).cloned().unwrap_or_default()
 | 
						|
    }
 | 
						|
 | 
						|
    /// Consume all the whitespace
 | 
						|
    pub fn consume_ws(&mut self) {
 | 
						|
        while matches!(self.current_token().kind, SyntaxKind::Whitespace | SyntaxKind::Comment) {
 | 
						|
            self.consume()
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl Parser for DefaultParser<'_> {
 | 
						|
    fn start_node_impl(
 | 
						|
        &mut self,
 | 
						|
        kind: SyntaxKind,
 | 
						|
        checkpoint: Option<Self::Checkpoint>,
 | 
						|
        _: NodeToken,
 | 
						|
    ) {
 | 
						|
        if kind != SyntaxKind::Document {
 | 
						|
            self.consume_ws();
 | 
						|
        }
 | 
						|
        match checkpoint {
 | 
						|
            None => self.builder.start_node(kind.into()),
 | 
						|
            Some(cp) => self.builder.start_node_at(cp, kind.into()),
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    fn finish_node_impl(&mut self, _: NodeToken) {
 | 
						|
        self.builder.finish_node();
 | 
						|
    }
 | 
						|
 | 
						|
    /// Peek the `n`th token, not including whitespace and comments
 | 
						|
    fn nth(&mut self, mut n: usize) -> Token {
 | 
						|
        self.consume_ws();
 | 
						|
        let mut c = self.cursor;
 | 
						|
        while n > 0 {
 | 
						|
            n -= 1;
 | 
						|
            c += 1;
 | 
						|
            while c < self.tokens.len()
 | 
						|
                && matches!(self.tokens[c].kind, SyntaxKind::Whitespace | SyntaxKind::Comment)
 | 
						|
            {
 | 
						|
                c += 1;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        self.tokens.get(c).cloned().unwrap_or_default()
 | 
						|
    }
 | 
						|
 | 
						|
    /// Consume the current token
 | 
						|
    fn consume(&mut self) {
 | 
						|
        let t = self.current_token();
 | 
						|
        self.builder.token(t.kind.into(), t.text.as_str());
 | 
						|
        if t.kind != SyntaxKind::Eof {
 | 
						|
            self.cursor += 1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /// Reports an error at the current token location
 | 
						|
    fn error(&mut self, e: impl Into<String>) {
 | 
						|
        let current_token = self.current_token();
 | 
						|
        #[allow(unused_mut)]
 | 
						|
        let mut span = crate::diagnostics::Span::new(current_token.offset);
 | 
						|
        #[cfg(feature = "proc_macro_span")]
 | 
						|
        {
 | 
						|
            span.span = current_token.span;
 | 
						|
        }
 | 
						|
 | 
						|
        self.diags.push_error_with_span(
 | 
						|
            e.into(),
 | 
						|
            crate::diagnostics::SourceLocation {
 | 
						|
                source_file: Some(self.source_file.clone()),
 | 
						|
                span,
 | 
						|
            },
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    /// Reports an error at the current token location
 | 
						|
    fn warning(&mut self, e: impl Into<String>) {
 | 
						|
        let current_token = self.current_token();
 | 
						|
        #[allow(unused_mut)]
 | 
						|
        let mut span = crate::diagnostics::Span::new(current_token.offset);
 | 
						|
        #[cfg(feature = "proc_macro_span")]
 | 
						|
        {
 | 
						|
            span.span = current_token.span;
 | 
						|
        }
 | 
						|
 | 
						|
        self.diags.push_warning_with_span(
 | 
						|
            e.into(),
 | 
						|
            crate::diagnostics::SourceLocation {
 | 
						|
                source_file: Some(self.source_file.clone()),
 | 
						|
                span,
 | 
						|
            },
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    type Checkpoint = rowan::Checkpoint;
 | 
						|
    fn checkpoint(&mut self) -> Self::Checkpoint {
 | 
						|
        self.builder.checkpoint()
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Clone, Copy, Debug, Eq, Ord, Hash, PartialEq, PartialOrd)]
 | 
						|
pub enum Language {}
 | 
						|
impl rowan::Language for Language {
 | 
						|
    type Kind = SyntaxKind;
 | 
						|
    fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind {
 | 
						|
        SyntaxKind::try_from(raw.0).unwrap()
 | 
						|
    }
 | 
						|
    fn kind_to_raw(kind: Self::Kind) -> rowan::SyntaxKind {
 | 
						|
        kind.into()
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Debug, Clone, derive_more::Deref)]
 | 
						|
pub struct SyntaxNode {
 | 
						|
    #[deref]
 | 
						|
    pub node: rowan::SyntaxNode<Language>,
 | 
						|
    pub source_file: SourceFile,
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Debug, Clone, derive_more::Deref)]
 | 
						|
pub struct SyntaxToken {
 | 
						|
    #[deref]
 | 
						|
    pub token: rowan::SyntaxToken<Language>,
 | 
						|
    pub source_file: SourceFile,
 | 
						|
}
 | 
						|
 | 
						|
impl SyntaxToken {
 | 
						|
    pub fn parent(&self) -> SyntaxNode {
 | 
						|
        SyntaxNode { node: self.token.parent().unwrap(), source_file: self.source_file.clone() }
 | 
						|
    }
 | 
						|
    pub fn parent_ancestors(&self) -> impl Iterator<Item = SyntaxNode> + '_ {
 | 
						|
        self.token
 | 
						|
            .parent_ancestors()
 | 
						|
            .map(|node| SyntaxNode { node, source_file: self.source_file.clone() })
 | 
						|
    }
 | 
						|
    pub fn next_token(&self) -> Option<SyntaxToken> {
 | 
						|
        // Due to a bug (as of rowan 0.15.3), rowan::SyntaxToken::next_token doesn't work if a
 | 
						|
        // sibling don't have tokens.
 | 
						|
        // For example, if we have an expression like  `if (true) {}`  the
 | 
						|
        // ConditionalExpression has an empty Expression/CodeBlock  for the else part,
 | 
						|
        // and next_token doesn't go into that.
 | 
						|
        // So re-implement
 | 
						|
 | 
						|
        let token = self
 | 
						|
            .token
 | 
						|
            .next_sibling_or_token()
 | 
						|
            .and_then(|e| match e {
 | 
						|
                rowan::NodeOrToken::Node(n) => n.first_token(),
 | 
						|
                rowan::NodeOrToken::Token(t) => Some(t),
 | 
						|
            })
 | 
						|
            .or_else(|| {
 | 
						|
                self.token.parent_ancestors().find_map(|it| it.next_sibling_or_token()).and_then(
 | 
						|
                    |e| match e {
 | 
						|
                        rowan::NodeOrToken::Node(n) => n.first_token(),
 | 
						|
                        rowan::NodeOrToken::Token(t) => Some(t),
 | 
						|
                    },
 | 
						|
                )
 | 
						|
            })?;
 | 
						|
        Some(SyntaxToken { token, source_file: self.source_file.clone() })
 | 
						|
    }
 | 
						|
    pub fn prev_token(&self) -> Option<SyntaxToken> {
 | 
						|
        let token = self.token.prev_token()?;
 | 
						|
        Some(SyntaxToken { token, source_file: self.source_file.clone() })
 | 
						|
    }
 | 
						|
    pub fn text(&self) -> &str {
 | 
						|
        self.token.text()
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl std::fmt::Display for SyntaxToken {
 | 
						|
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
						|
        self.token.fmt(f)
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl SyntaxNode {
 | 
						|
    pub fn child_node(&self, kind: SyntaxKind) -> Option<SyntaxNode> {
 | 
						|
        self.node
 | 
						|
            .children()
 | 
						|
            .find(|n| n.kind() == kind)
 | 
						|
            .map(|node| SyntaxNode { node, source_file: self.source_file.clone() })
 | 
						|
    }
 | 
						|
    pub fn child_token(&self, kind: SyntaxKind) -> Option<SyntaxToken> {
 | 
						|
        self.node
 | 
						|
            .children_with_tokens()
 | 
						|
            .find(|n| n.kind() == kind)
 | 
						|
            .and_then(|x| x.into_token())
 | 
						|
            .map(|token| SyntaxToken { token, source_file: self.source_file.clone() })
 | 
						|
    }
 | 
						|
    pub fn child_text(&self, kind: SyntaxKind) -> Option<SmolStr> {
 | 
						|
        self.node
 | 
						|
            .children_with_tokens()
 | 
						|
            .find(|n| n.kind() == kind)
 | 
						|
            .and_then(|x| x.as_token().map(|x| x.text().into()))
 | 
						|
    }
 | 
						|
    pub fn descendants(&self) -> impl Iterator<Item = SyntaxNode> {
 | 
						|
        let source_file = self.source_file.clone();
 | 
						|
        self.node
 | 
						|
            .descendants()
 | 
						|
            .map(move |node| SyntaxNode { node, source_file: source_file.clone() })
 | 
						|
    }
 | 
						|
    pub fn kind(&self) -> SyntaxKind {
 | 
						|
        self.node.kind()
 | 
						|
    }
 | 
						|
    pub fn children(&self) -> impl Iterator<Item = SyntaxNode> {
 | 
						|
        let source_file = self.source_file.clone();
 | 
						|
        self.node.children().map(move |node| SyntaxNode { node, source_file: source_file.clone() })
 | 
						|
    }
 | 
						|
    pub fn children_with_tokens(&self) -> impl Iterator<Item = NodeOrToken> {
 | 
						|
        let source_file = self.source_file.clone();
 | 
						|
        self.node.children_with_tokens().map(move |token| match token {
 | 
						|
            rowan::NodeOrToken::Node(node) => {
 | 
						|
                SyntaxNode { node, source_file: source_file.clone() }.into()
 | 
						|
            }
 | 
						|
            rowan::NodeOrToken::Token(token) => {
 | 
						|
                SyntaxToken { token, source_file: source_file.clone() }.into()
 | 
						|
            }
 | 
						|
        })
 | 
						|
    }
 | 
						|
    pub fn text(&self) -> rowan::SyntaxText {
 | 
						|
        self.node.text()
 | 
						|
    }
 | 
						|
    pub fn parent(&self) -> Option<SyntaxNode> {
 | 
						|
        self.node.parent().map(|node| SyntaxNode { node, source_file: self.source_file.clone() })
 | 
						|
    }
 | 
						|
    pub fn first_token(&self) -> Option<SyntaxToken> {
 | 
						|
        self.node
 | 
						|
            .first_token()
 | 
						|
            .map(|token| SyntaxToken { token, source_file: self.source_file.clone() })
 | 
						|
    }
 | 
						|
    pub fn last_token(&self) -> Option<SyntaxToken> {
 | 
						|
        self.node
 | 
						|
            .last_token()
 | 
						|
            .map(|token| SyntaxToken { token, source_file: self.source_file.clone() })
 | 
						|
    }
 | 
						|
    pub fn token_at_offset(&self, offset: TextSize) -> rowan::TokenAtOffset<SyntaxToken> {
 | 
						|
        self.node
 | 
						|
            .token_at_offset(offset)
 | 
						|
            .map(|token| SyntaxToken { token, source_file: self.source_file.clone() })
 | 
						|
    }
 | 
						|
    pub fn first_child(&self) -> Option<SyntaxNode> {
 | 
						|
        self.node
 | 
						|
            .first_child()
 | 
						|
            .map(|node| SyntaxNode { node, source_file: self.source_file.clone() })
 | 
						|
    }
 | 
						|
    pub fn first_child_or_token(&self) -> Option<NodeOrToken> {
 | 
						|
        self.node.first_child_or_token().map(|n_o_t| match n_o_t {
 | 
						|
            rowan::NodeOrToken::Node(node) => {
 | 
						|
                NodeOrToken::Node(SyntaxNode { node, source_file: self.source_file.clone() })
 | 
						|
            }
 | 
						|
            rowan::NodeOrToken::Token(token) => {
 | 
						|
                NodeOrToken::Token(SyntaxToken { token, source_file: self.source_file.clone() })
 | 
						|
            }
 | 
						|
        })
 | 
						|
    }
 | 
						|
    pub fn next_sibling(&self) -> Option<SyntaxNode> {
 | 
						|
        self.node
 | 
						|
            .next_sibling()
 | 
						|
            .map(|node| SyntaxNode { node, source_file: self.source_file.clone() })
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Debug, Clone, derive_more::From)]
 | 
						|
pub enum NodeOrToken {
 | 
						|
    Node(SyntaxNode),
 | 
						|
    Token(SyntaxToken),
 | 
						|
}
 | 
						|
 | 
						|
impl NodeOrToken {
 | 
						|
    pub fn kind(&self) -> SyntaxKind {
 | 
						|
        match self {
 | 
						|
            NodeOrToken::Node(n) => n.kind(),
 | 
						|
            NodeOrToken::Token(t) => t.kind(),
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    pub fn as_node(&self) -> Option<&SyntaxNode> {
 | 
						|
        match self {
 | 
						|
            NodeOrToken::Node(n) => Some(n),
 | 
						|
            NodeOrToken::Token(_) => None,
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    pub fn as_token(&self) -> Option<&SyntaxToken> {
 | 
						|
        match self {
 | 
						|
            NodeOrToken::Node(_) => None,
 | 
						|
            NodeOrToken::Token(t) => Some(t),
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    pub fn into_token(self) -> Option<SyntaxToken> {
 | 
						|
        match self {
 | 
						|
            NodeOrToken::Token(t) => Some(t),
 | 
						|
            _ => None,
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    pub fn into_node(self) -> Option<SyntaxNode> {
 | 
						|
        match self {
 | 
						|
            NodeOrToken::Node(n) => Some(n),
 | 
						|
            _ => None,
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    pub fn text_range(&self) -> TextRange {
 | 
						|
        match self {
 | 
						|
            NodeOrToken::Node(n) => n.text_range(),
 | 
						|
            NodeOrToken::Token(t) => t.text_range(),
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl Spanned for SyntaxNode {
 | 
						|
    fn span(&self) -> crate::diagnostics::Span {
 | 
						|
        crate::diagnostics::Span::new(self.node.text_range().start().into())
 | 
						|
    }
 | 
						|
 | 
						|
    fn source_file(&self) -> Option<&SourceFile> {
 | 
						|
        Some(&self.source_file)
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl Spanned for Option<SyntaxNode> {
 | 
						|
    fn span(&self) -> crate::diagnostics::Span {
 | 
						|
        self.as_ref().map(|n| n.span()).unwrap_or_default()
 | 
						|
    }
 | 
						|
 | 
						|
    fn source_file(&self) -> Option<&SourceFile> {
 | 
						|
        self.as_ref().and_then(|n| n.source_file())
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl Spanned for SyntaxToken {
 | 
						|
    fn span(&self) -> crate::diagnostics::Span {
 | 
						|
        crate::diagnostics::Span::new(self.token.text_range().start().into())
 | 
						|
    }
 | 
						|
 | 
						|
    fn source_file(&self) -> Option<&SourceFile> {
 | 
						|
        Some(&self.source_file)
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl Spanned for NodeOrToken {
 | 
						|
    fn span(&self) -> crate::diagnostics::Span {
 | 
						|
        match self {
 | 
						|
            NodeOrToken::Node(n) => n.span(),
 | 
						|
            NodeOrToken::Token(t) => t.span(),
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    fn source_file(&self) -> Option<&SourceFile> {
 | 
						|
        match self {
 | 
						|
            NodeOrToken::Node(n) => n.source_file(),
 | 
						|
            NodeOrToken::Token(t) => t.source_file(),
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl Spanned for Option<NodeOrToken> {
 | 
						|
    fn span(&self) -> crate::diagnostics::Span {
 | 
						|
        self.as_ref().map(|t| t.span()).unwrap_or_default()
 | 
						|
    }
 | 
						|
    fn source_file(&self) -> Option<&SourceFile> {
 | 
						|
        self.as_ref().and_then(|t| t.source_file())
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl Spanned for Option<SyntaxToken> {
 | 
						|
    fn span(&self) -> crate::diagnostics::Span {
 | 
						|
        self.as_ref().map(|t| t.span()).unwrap_or_default()
 | 
						|
    }
 | 
						|
    fn source_file(&self) -> Option<&SourceFile> {
 | 
						|
        self.as_ref().and_then(|t| t.source_file())
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/// return the normalized identifier string of the first SyntaxKind::Identifier in this node
 | 
						|
pub fn identifier_text(node: &SyntaxNode) -> Option<SmolStr> {
 | 
						|
    node.child_text(SyntaxKind::Identifier).map(|x| normalize_identifier(&x))
 | 
						|
}
 | 
						|
 | 
						|
pub fn normalize_identifier(ident: &str) -> SmolStr {
 | 
						|
    ident.replace_smolstr("_", "-")
 | 
						|
}
 | 
						|
 | 
						|
// Actual parser
 | 
						|
pub fn parse(
 | 
						|
    source: String,
 | 
						|
    path: Option<&std::path::Path>,
 | 
						|
    build_diagnostics: &mut BuildDiagnostics,
 | 
						|
) -> SyntaxNode {
 | 
						|
    let mut p = DefaultParser::new(&source, build_diagnostics);
 | 
						|
    p.source_file = std::rc::Rc::new(crate::diagnostics::SourceFileInner::new(
 | 
						|
        path.map(crate::pathutils::clean_path).unwrap_or_default(),
 | 
						|
        source,
 | 
						|
    ));
 | 
						|
    document::parse_document(&mut p);
 | 
						|
    SyntaxNode {
 | 
						|
        node: rowan::SyntaxNode::new_root(p.builder.finish()),
 | 
						|
        source_file: p.source_file.clone(),
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
pub fn parse_file<P: AsRef<std::path::Path>>(
 | 
						|
    path: P,
 | 
						|
    build_diagnostics: &mut BuildDiagnostics,
 | 
						|
) -> Option<SyntaxNode> {
 | 
						|
    let path = crate::pathutils::clean_path(path.as_ref());
 | 
						|
    let source = crate::diagnostics::load_from_path(&path)
 | 
						|
        .map_err(|d| build_diagnostics.push_internal_error(d))
 | 
						|
        .ok()?;
 | 
						|
    Some(parse(source, Some(path.as_ref()), build_diagnostics))
 | 
						|
}
 | 
						|
 | 
						|
pub fn parse_tokens(
 | 
						|
    tokens: Vec<Token>,
 | 
						|
    source_file: SourceFile,
 | 
						|
    diags: &mut BuildDiagnostics,
 | 
						|
) -> SyntaxNode {
 | 
						|
    let mut p = DefaultParser::from_tokens(tokens, diags);
 | 
						|
    document::parse_document(&mut p);
 | 
						|
    SyntaxNode { node: rowan::SyntaxNode::new_root(p.builder.finish()), source_file }
 | 
						|
}
 |