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 | |
6 | This module is responsible to parse a string onto a syntax tree. |
7 | |
8 | The core of it is the `DefaultParser` class that holds a list of token and |
9 | generates a `rowan::GreenNode` |
10 | |
11 | This module has different sub modules with the actual parser functions |
12 | |
13 | */ |
14 | |
15 | use crate::diagnostics::{BuildDiagnostics, SourceFile, SourceFileVersion, Spanned}; |
16 | pub use smol_str::SmolStr; |
17 | use std::fmt::Display; |
18 | |
19 | mod document; |
20 | mod element; |
21 | mod expressions; |
22 | mod statements; |
23 | mod r#type; |
24 | |
25 | /// Each parser submodule would simply do `use super::prelude::*` to import typically used items |
26 | mod 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)] |
37 | pub 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 | |
47 | pub use rowan::{TextRange, TextSize}; |
48 | |
49 | /// Check that a node has the assumed children |
50 | #[cfg (test)] |
51 | macro_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 | |
101 | macro_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. |
180 | macro_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 | } |
277 | declare_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 | |
445 | impl From<SyntaxKind> for rowan::SyntaxKind { |
446 | fn from(v: SyntaxKind) -> Self { |
447 | rowan::SyntaxKind(v.into()) |
448 | } |
449 | } |
450 | |
451 | #[derive (Clone, Debug)] |
452 | pub 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 | |
460 | impl 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 | |
472 | impl 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 | |
482 | mod 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)] |
598 | pub use parser_trait::*; |
599 | |
600 | pub 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 | |
608 | impl<'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 | |
636 | impl 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)] |
726 | pub enum Language {} |
727 | impl 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)] |
738 | pub struct SyntaxNode { |
739 | #[deref] |
740 | pub node: rowan::SyntaxNode<Language>, |
741 | pub source_file: SourceFile, |
742 | } |
743 | |
744 | #[derive (Debug, Clone, derive_more::Deref)] |
745 | pub struct SyntaxToken { |
746 | #[deref] |
747 | pub token: rowan::SyntaxToken<Language>, |
748 | pub source_file: SourceFile, |
749 | } |
750 | |
751 | impl 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 | |
785 | impl 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 | |
791 | impl 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)] |
843 | pub enum NodeOrToken { |
844 | Node(SyntaxNode), |
845 | Token(SyntaxToken), |
846 | } |
847 | |
848 | impl 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 | |
892 | impl 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 | |
902 | impl 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 | |
912 | impl 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 | |
922 | impl 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 | |
938 | impl 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 | |
947 | impl 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 |
957 | pub fn identifier_text(node: &SyntaxNode) -> Option<String> { |
958 | node.child_text(kind:SyntaxKind::Identifier).map(|x: String| normalize_identifier(&x)) |
959 | } |
960 | |
961 | pub 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. |
967 | pub 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 |
1000 | pub 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 | |
1019 | pub 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 | |
1030 | pub 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 | |