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