Skip to main content

wdl_grammar/
tree.rs

1//! Module for the concrete syntax tree (CST) representation.
2
3pub mod dive;
4
5use std::borrow::Cow;
6use std::collections::VecDeque;
7use std::fmt;
8use std::iter;
9
10use rowan::GreenNodeBuilder;
11use rowan::GreenNodeData;
12use strum::VariantArray;
13
14use super::Diagnostic;
15use super::grammar;
16use super::lexer::Lexer;
17use super::parser::Event;
18use crate::parser::Parser;
19
20/// Represents the kind of syntax element (node or token) in a WDL concrete
21/// syntax tree (CST).
22///
23/// Nodes have at least one token child and represent a syntactic construct.
24///
25/// Tokens are terminal and represent any span of the source.
26///
27/// This enumeration is a union of all supported WDL tokens and nodes.
28#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, VariantArray)]
29#[repr(u16)]
30pub enum SyntaxKind {
31    /// The token is unknown to WDL.
32    Unknown,
33    /// The token represents unparsed source.
34    ///
35    /// Unparsed source occurs in WDL source files with unsupported versions.
36    Unparsed,
37    /// A whitespace token.
38    Whitespace,
39    /// A comment token.
40    Comment,
41    /// A WDL version token.
42    Version,
43    /// A literal float token.
44    Float,
45    /// A literal integer token.
46    Integer,
47    /// An identifier token.
48    Ident,
49    /// A single quote token.
50    SingleQuote,
51    /// A double quote token.
52    DoubleQuote,
53    /// An open heredoc token.
54    OpenHeredoc,
55    /// A close heredoc token.
56    CloseHeredoc,
57    /// The `Array` type keyword token.
58    ArrayTypeKeyword,
59    /// The `Boolean` type keyword token.
60    BooleanTypeKeyword,
61    /// The `File` type keyword token.
62    FileTypeKeyword,
63    /// The `Float` type keyword token.
64    FloatTypeKeyword,
65    /// The `Int` type keyword token.
66    IntTypeKeyword,
67    /// The `Map` type keyword token.
68    MapTypeKeyword,
69    /// The `Object` type keyword token.
70    ObjectTypeKeyword,
71    /// The `Pair` type keyword token.
72    PairTypeKeyword,
73    /// The `String` type keyword token.
74    StringTypeKeyword,
75    /// The `after` keyword token.
76    AfterKeyword,
77    /// The `alias` keyword token.
78    AliasKeyword,
79    /// The `as` keyword token.
80    AsKeyword,
81    /// The `call` keyword token.
82    CallKeyword,
83    /// The `command` keyword token.
84    CommandKeyword,
85    /// The `else` keyword token.
86    ElseKeyword,
87    /// The `env` keyword token.
88    EnvKeyword,
89    /// The `false` keyword token.
90    FalseKeyword,
91    /// The `if` keyword token.
92    IfKeyword,
93    /// The `in` keyword token.
94    InKeyword,
95    /// The `import` keyword token.
96    ImportKeyword,
97    /// The `input` keyword token.
98    InputKeyword,
99    /// The `meta` keyword token.
100    MetaKeyword,
101    /// The `None` keyword.
102    NoneKeyword,
103    /// The `null` keyword token.
104    NullKeyword,
105    /// The `object` keyword token.
106    ObjectKeyword,
107    /// The `output` keyword token.
108    OutputKeyword,
109    /// The `parameter_meta` keyword token.
110    ParameterMetaKeyword,
111    /// The `runtime` keyword token.
112    RuntimeKeyword,
113    /// The `scatter` keyword token.
114    ScatterKeyword,
115    /// The `struct` keyword token.
116    StructKeyword,
117    /// The `enum` keyword token.
118    EnumKeyword,
119    /// The `task` keyword token.
120    TaskKeyword,
121    /// The `then` keyword token.
122    ThenKeyword,
123    /// The `true` keyword token.
124    TrueKeyword,
125    /// The `version` keyword token.
126    VersionKeyword,
127    /// The `workflow` keyword token.
128    WorkflowKeyword,
129    /// The 1.2 `Directory` type keyword token.
130    DirectoryTypeKeyword,
131    /// The 1.2 `hints` keyword token.
132    HintsKeyword,
133    /// The 1.2 `requirements` keyword token.
134    RequirementsKeyword,
135    /// The `{` symbol token.
136    OpenBrace,
137    /// The `}` symbol token.
138    CloseBrace,
139    /// The `[` symbol token.
140    OpenBracket,
141    /// The `]` symbol token.
142    CloseBracket,
143    /// The `=` symbol token.
144    Assignment,
145    /// The `:` symbol token.
146    Colon,
147    /// The `,` symbol token.
148    Comma,
149    /// The `(` symbol token.
150    OpenParen,
151    /// The `)` symbol token.
152    CloseParen,
153    /// The `?` symbol token.
154    QuestionMark,
155    /// The `!` symbol token.
156    Exclamation,
157    /// The `+` symbol token.
158    Plus,
159    /// The `-` symbol token.
160    Minus,
161    /// The `||` symbol token.
162    LogicalOr,
163    /// The `&&` symbol token.
164    LogicalAnd,
165    /// The `*` symbol token.
166    Asterisk,
167    /// The `**` symbol token.
168    Exponentiation,
169    /// The `/` symbol token.
170    Slash,
171    /// The `%` symbol token.
172    Percent,
173    /// The `==` symbol token.
174    Equal,
175    /// The `!=` symbol token.
176    NotEqual,
177    /// The `<=` symbol token.
178    LessEqual,
179    /// The `>=` symbol token.
180    GreaterEqual,
181    /// The `<` symbol token.
182    Less,
183    /// The `>` symbol token.
184    Greater,
185    /// The `.` symbol token.
186    Dot,
187    /// A literal text part of a string.
188    LiteralStringText,
189    /// A literal text part of a command.
190    LiteralCommandText,
191    /// A placeholder open token.
192    PlaceholderOpen,
193
194    /// Abandoned nodes are nodes that encountered errors.
195    ///
196    /// Children of abandoned nodes are re-parented to the parent of
197    /// the abandoned node.
198    ///
199    /// As this is an internal implementation of error recovery,
200    /// hide this variant from the documentation.
201    #[doc(hidden)]
202    Abandoned,
203    /// Represents the WDL document root node.
204    RootNode,
205    /// Represents a version statement node.
206    VersionStatementNode,
207    /// Represents an import statement node.
208    ImportStatementNode,
209    /// Represents an import alias node.
210    ImportAliasNode,
211    /// Represents a struct definition node.
212    StructDefinitionNode,
213    /// Represents an enum definition node.
214    EnumDefinitionNode,
215    /// Represents an enum type parameter node.
216    EnumTypeParameterNode,
217    /// Represents an enum variant node.
218    EnumVariantNode,
219    /// Represents a task definition node.
220    TaskDefinitionNode,
221    /// Represents a workflow definition node.
222    WorkflowDefinitionNode,
223    /// Represents an unbound declaration node.
224    UnboundDeclNode,
225    /// Represents a bound declaration node.
226    BoundDeclNode,
227    /// Represents an input section node.
228    InputSectionNode,
229    /// Represents an output section node.
230    OutputSectionNode,
231    /// Represents a command section node.
232    CommandSectionNode,
233    /// Represents a requirements section node.
234    RequirementsSectionNode,
235    /// Represents a requirements item node.
236    RequirementsItemNode,
237    /// Represents a hints section node in a task.
238    TaskHintsSectionNode,
239    /// Represents a hints section node in a workflow.
240    WorkflowHintsSectionNode,
241    /// Represents a hints item node in a task.
242    TaskHintsItemNode,
243    /// Represents a hints item node in a workflow.
244    WorkflowHintsItemNode,
245    /// Represents a literal object in a workflow hints item value.
246    WorkflowHintsObjectNode,
247    /// Represents an item in a workflow hints object.
248    WorkflowHintsObjectItemNode,
249    /// Represents a literal array in a workflow hints item value.
250    WorkflowHintsArrayNode,
251    /// Represents a runtime section node.
252    RuntimeSectionNode,
253    /// Represents a runtime item node.
254    RuntimeItemNode,
255    /// Represents a primitive type node.
256    PrimitiveTypeNode,
257    /// Represents a map type node.
258    MapTypeNode,
259    /// Represents an array type node.
260    ArrayTypeNode,
261    /// Represents a pair type node.
262    PairTypeNode,
263    /// Represents an object type node.
264    ObjectTypeNode,
265    /// Represents a type reference node.
266    TypeRefNode,
267    /// Represents a metadata section node.
268    MetadataSectionNode,
269    /// Represents a parameter metadata section node.
270    ParameterMetadataSectionNode,
271    /// Represents a metadata object item node.
272    MetadataObjectItemNode,
273    /// Represents a metadata object node.
274    MetadataObjectNode,
275    /// Represents a metadata array node.
276    MetadataArrayNode,
277    /// Represents a literal integer node.
278    LiteralIntegerNode,
279    /// Represents a literal float node.
280    LiteralFloatNode,
281    /// Represents a literal boolean node.
282    LiteralBooleanNode,
283    /// Represents a literal `None` node.
284    LiteralNoneNode,
285    /// Represents a literal null node.
286    LiteralNullNode,
287    /// Represents a literal string node.
288    LiteralStringNode,
289    /// Represents a literal pair node.
290    LiteralPairNode,
291    /// Represents a literal array node.
292    LiteralArrayNode,
293    /// Represents a literal map node.
294    LiteralMapNode,
295    /// Represents a literal map item node.
296    LiteralMapItemNode,
297    /// Represents a literal object node.
298    LiteralObjectNode,
299    /// Represents a literal object item node.
300    LiteralObjectItemNode,
301    /// Represents a literal struct node.
302    LiteralStructNode,
303    /// Represents a literal struct item node.
304    LiteralStructItemNode,
305    /// Represents a literal hints node.
306    LiteralHintsNode,
307    /// Represents a literal hints item node.
308    LiteralHintsItemNode,
309    /// Represents a literal input node.
310    LiteralInputNode,
311    /// Represents a literal input item node.
312    LiteralInputItemNode,
313    /// Represents a literal output node.
314    LiteralOutputNode,
315    /// Represents a literal output item node.
316    LiteralOutputItemNode,
317    /// Represents a parenthesized expression node.
318    ParenthesizedExprNode,
319    /// Represents a name reference expression node.
320    NameRefExprNode,
321    /// Represents an `if` expression node.
322    IfExprNode,
323    /// Represents a logical not expression node.
324    LogicalNotExprNode,
325    /// Represents a negation expression node.
326    NegationExprNode,
327    /// Represents a logical `OR` expression node.
328    LogicalOrExprNode,
329    /// Represents a logical `AND` expression node.
330    LogicalAndExprNode,
331    /// Represents an equality expression node.
332    EqualityExprNode,
333    /// Represents an inequality expression node.
334    InequalityExprNode,
335    /// Represents a "less than" expression node.
336    LessExprNode,
337    /// Represents a "less than or equal to" expression node.
338    LessEqualExprNode,
339    /// Represents a "greater than" expression node.
340    GreaterExprNode,
341    /// Represents a "greater than or equal to" expression node.
342    GreaterEqualExprNode,
343    /// Represents an addition expression node.
344    AdditionExprNode,
345    /// Represents a subtraction expression node.
346    SubtractionExprNode,
347    /// Represents a multiplication expression node.
348    MultiplicationExprNode,
349    /// Represents a division expression node.
350    DivisionExprNode,
351    /// Represents a modulo expression node.
352    ModuloExprNode,
353    /// Represents a exponentiation expr node.
354    ExponentiationExprNode,
355    /// Represents a call expression node.'
356    CallExprNode,
357    /// Represents an index expression node.
358    IndexExprNode,
359    /// Represents an an access expression node.
360    AccessExprNode,
361    /// Represents a placeholder node in a string literal.
362    PlaceholderNode,
363    /// Placeholder `sep` option node.
364    PlaceholderSepOptionNode,
365    /// Placeholder `default` option node.
366    PlaceholderDefaultOptionNode,
367    /// Placeholder `true`/`false` option node.
368    PlaceholderTrueFalseOptionNode,
369    /// Represents a conditional statement node.
370    ConditionalStatementNode,
371    /// Represents a clause within a conditional statement.
372    ConditionalStatementClauseNode,
373    /// Represents a scatter statement node.
374    ScatterStatementNode,
375    /// Represents a call statement node.
376    CallStatementNode,
377    /// Represents a call target node in a call statement.
378    CallTargetNode,
379    /// Represents a call alias node in a call statement.
380    CallAliasNode,
381    /// Represents an `after` clause node in a call statement.
382    CallAfterNode,
383    /// Represents a call input item node.
384    CallInputItemNode,
385
386    // WARNING: this must always be the last variant.
387    /// The exclusive maximum syntax kind value.
388    MAX,
389}
390
391impl SyntaxKind {
392    /// Returns whether the token is a symbolic [`SyntaxKind`].
393    ///
394    /// Generally speaking, symbolic [`SyntaxKind`]s have special meanings
395    /// during parsing—they are not real elements of the grammar but rather an
396    /// implementation detail.
397    pub fn is_symbolic(&self) -> bool {
398        matches!(
399            self,
400            Self::Abandoned | Self::Unknown | Self::Unparsed | Self::MAX
401        )
402    }
403
404    /// Describes the syntax kind.
405    pub fn describe(&self) -> &'static str {
406        match self {
407            Self::Unknown => unreachable!(),
408            Self::Unparsed => unreachable!(),
409            Self::Whitespace => "whitespace",
410            Self::Comment => "comment",
411            Self::Version => "version",
412            Self::Float => "float",
413            Self::Integer => "integer",
414            Self::Ident => "identifier",
415            Self::SingleQuote => "single quote",
416            Self::DoubleQuote => "double quote",
417            Self::OpenHeredoc => "open heredoc",
418            Self::CloseHeredoc => "close heredoc",
419            Self::ArrayTypeKeyword => "`Array` type keyword",
420            Self::BooleanTypeKeyword => "`Boolean` type keyword",
421            Self::FileTypeKeyword => "`File` type keyword",
422            Self::FloatTypeKeyword => "`Float` type keyword",
423            Self::IntTypeKeyword => "`Int` type keyword",
424            Self::MapTypeKeyword => "`Map` type keyword",
425            Self::ObjectTypeKeyword => "`Object` type keyword",
426            Self::PairTypeKeyword => "`Pair` type keyword",
427            Self::StringTypeKeyword => "`String` type keyword",
428            Self::AfterKeyword => "`after` keyword",
429            Self::AliasKeyword => "`alias` keyword",
430            Self::AsKeyword => "`as` keyword",
431            Self::CallKeyword => "`call` keyword",
432            Self::CommandKeyword => "`command` keyword",
433            Self::ElseKeyword => "`else` keyword",
434            Self::EnvKeyword => "`env` keyword",
435            Self::FalseKeyword => "`false` keyword",
436            Self::IfKeyword => "`if` keyword",
437            Self::InKeyword => "`in` keyword",
438            Self::ImportKeyword => "`import` keyword",
439            Self::InputKeyword => "`input` keyword",
440            Self::MetaKeyword => "`meta` keyword",
441            Self::NoneKeyword => "`None` keyword",
442            Self::NullKeyword => "`null` keyword",
443            Self::ObjectKeyword => "`object` keyword",
444            Self::OutputKeyword => "`output` keyword",
445            Self::ParameterMetaKeyword => "`parameter_meta` keyword",
446            Self::RuntimeKeyword => "`runtime` keyword",
447            Self::ScatterKeyword => "`scatter` keyword",
448            Self::StructKeyword => "`struct` keyword",
449            Self::EnumKeyword => "`enum` keyword",
450            Self::TaskKeyword => "`task` keyword",
451            Self::ThenKeyword => "`then` keyword",
452            Self::TrueKeyword => "`true` keyword",
453            Self::VersionKeyword => "`version` keyword",
454            Self::WorkflowKeyword => "`workflow` keyword",
455            Self::DirectoryTypeKeyword => "`Directory` type keyword",
456            Self::HintsKeyword => "`hints` keyword",
457            Self::RequirementsKeyword => "`requirements` keyword",
458            Self::OpenBrace => "`{` symbol",
459            Self::CloseBrace => "`}` symbol",
460            Self::OpenBracket => "`[` symbol",
461            Self::CloseBracket => "`]` symbol",
462            Self::Assignment => "`=` symbol",
463            Self::Colon => "`:` symbol",
464            Self::Comma => "`,` symbol",
465            Self::OpenParen => "`(` symbol",
466            Self::CloseParen => "`)` symbol",
467            Self::QuestionMark => "`?` symbol",
468            Self::Exclamation => "`!` symbol",
469            Self::Plus => "`+` symbol",
470            Self::Minus => "`-` symbol",
471            Self::LogicalOr => "`||` symbol",
472            Self::LogicalAnd => "`&&` symbol",
473            Self::Asterisk => "`*` symbol",
474            Self::Exponentiation => "`**` symbol",
475            Self::Slash => "`/` symbol",
476            Self::Percent => "`%` symbol",
477            Self::Equal => "`==` symbol",
478            Self::NotEqual => "`!=` symbol",
479            Self::LessEqual => "`<=` symbol",
480            Self::GreaterEqual => "`>=` symbol",
481            Self::Less => "`<` symbol",
482            Self::Greater => "`>` symbol",
483            Self::Dot => "`.` symbol",
484            Self::LiteralStringText => "literal string text",
485            Self::LiteralCommandText => "literal command text",
486            Self::PlaceholderOpen => "placeholder open",
487            Self::Abandoned => unreachable!(),
488            Self::RootNode => "root node",
489            Self::VersionStatementNode => "version statement",
490            Self::ImportStatementNode => "import statement",
491            Self::ImportAliasNode => "import alias",
492            Self::StructDefinitionNode => "struct definition",
493            Self::EnumDefinitionNode => "enum definition",
494            Self::EnumTypeParameterNode => "enum type parameter",
495            Self::EnumVariantNode => "enum variant",
496            Self::TaskDefinitionNode => "task definition",
497            Self::WorkflowDefinitionNode => "workflow definition",
498            Self::UnboundDeclNode => "declaration without assignment",
499            Self::BoundDeclNode => "declaration with assignment",
500            Self::InputSectionNode => "input section",
501            Self::OutputSectionNode => "output section",
502            Self::CommandSectionNode => "command section",
503            Self::RequirementsSectionNode => "requirements section",
504            Self::RequirementsItemNode => "requirements item",
505            Self::TaskHintsSectionNode | Self::WorkflowHintsSectionNode => "hints section",
506            Self::TaskHintsItemNode | Self::WorkflowHintsItemNode => "hints item",
507            Self::WorkflowHintsObjectNode => "literal object",
508            Self::WorkflowHintsObjectItemNode => "literal object item",
509            Self::WorkflowHintsArrayNode => "literal array",
510            Self::RuntimeSectionNode => "runtime section",
511            Self::RuntimeItemNode => "runtime item",
512            Self::PrimitiveTypeNode => "primitive type",
513            Self::MapTypeNode => "map type",
514            Self::ArrayTypeNode => "array type",
515            Self::PairTypeNode => "pair type",
516            Self::ObjectTypeNode => "object type",
517            Self::TypeRefNode => "type reference",
518            Self::MetadataSectionNode => "metadata section",
519            Self::ParameterMetadataSectionNode => "parameter metadata section",
520            Self::MetadataObjectItemNode => "metadata object item",
521            Self::MetadataObjectNode => "metadata object",
522            Self::MetadataArrayNode => "metadata array",
523            Self::LiteralIntegerNode => "literal integer",
524            Self::LiteralFloatNode => "literal float",
525            Self::LiteralBooleanNode => "literal boolean",
526            Self::LiteralNoneNode => "literal `None`",
527            Self::LiteralNullNode => "literal null",
528            Self::LiteralStringNode => "literal string",
529            Self::LiteralPairNode => "literal pair",
530            Self::LiteralArrayNode => "literal array",
531            Self::LiteralMapNode => "literal map",
532            Self::LiteralMapItemNode => "literal map item",
533            Self::LiteralObjectNode => "literal object",
534            Self::LiteralObjectItemNode => "literal object item",
535            Self::LiteralStructNode => "literal struct",
536            Self::LiteralStructItemNode => "literal struct item",
537            Self::LiteralHintsNode => "literal hints",
538            Self::LiteralHintsItemNode => "literal hints item",
539            Self::LiteralInputNode => "literal input",
540            Self::LiteralInputItemNode => "literal input item",
541            Self::LiteralOutputNode => "literal output",
542            Self::LiteralOutputItemNode => "literal output item",
543            Self::ParenthesizedExprNode => "parenthesized expression",
544            Self::NameRefExprNode => "name reference expression",
545            Self::IfExprNode => "`if` expression",
546            Self::LogicalNotExprNode => "logical not expression",
547            Self::NegationExprNode => "negation expression",
548            Self::LogicalOrExprNode => "logical OR expression",
549            Self::LogicalAndExprNode => "logical AND expression",
550            Self::EqualityExprNode => "equality expression",
551            Self::InequalityExprNode => "inequality expression",
552            Self::LessExprNode => "less than expression",
553            Self::LessEqualExprNode => "less than or equal to expression",
554            Self::GreaterExprNode => "greater than expression",
555            Self::GreaterEqualExprNode => "greater than or equal to expression",
556            Self::AdditionExprNode => "addition expression",
557            Self::SubtractionExprNode => "subtraction expression",
558            Self::MultiplicationExprNode => "multiplication expression",
559            Self::DivisionExprNode => "division expression",
560            Self::ModuloExprNode => "modulo expression",
561            Self::ExponentiationExprNode => "exponentiation expression",
562            Self::CallExprNode => "call expression",
563            Self::IndexExprNode => "index expression",
564            Self::AccessExprNode => "access expression",
565            Self::PlaceholderNode => "placeholder",
566            Self::PlaceholderSepOptionNode => "placeholder `sep` option",
567            Self::PlaceholderDefaultOptionNode => "placeholder `default` option",
568            Self::PlaceholderTrueFalseOptionNode => "placeholder `true`/`false` option",
569            Self::ConditionalStatementNode => "conditional statement",
570            Self::ConditionalStatementClauseNode => "conditional statement clause",
571            Self::ScatterStatementNode => "scatter statement",
572            Self::CallStatementNode => "call statement",
573            Self::CallTargetNode => "call target",
574            Self::CallAliasNode => "call alias",
575            Self::CallAfterNode => "call `after` clause",
576            Self::CallInputItemNode => "call input item",
577            Self::MAX => unreachable!(),
578        }
579    }
580
581    /// Returns whether the [`SyntaxKind`] is trivia.
582    pub fn is_trivia(&self) -> bool {
583        matches!(self, Self::Whitespace | Self::Comment)
584    }
585
586    /// Returns whether the [`SyntaxKind`] is a keyword.
587    pub fn is_keyword(&self) -> bool {
588        matches!(
589            self,
590            SyntaxKind::AfterKeyword
591                | SyntaxKind::AliasKeyword
592                | SyntaxKind::ArrayTypeKeyword
593                | SyntaxKind::AsKeyword
594                | SyntaxKind::BooleanTypeKeyword
595                | SyntaxKind::CallKeyword
596                | SyntaxKind::CommandKeyword
597                | SyntaxKind::DirectoryTypeKeyword
598                | SyntaxKind::ElseKeyword
599                | SyntaxKind::EnvKeyword
600                | SyntaxKind::FalseKeyword
601                | SyntaxKind::FileTypeKeyword
602                | SyntaxKind::FloatTypeKeyword
603                | SyntaxKind::HintsKeyword
604                | SyntaxKind::IfKeyword
605                | SyntaxKind::ImportKeyword
606                | SyntaxKind::InKeyword
607                | SyntaxKind::InputKeyword
608                | SyntaxKind::IntTypeKeyword
609                | SyntaxKind::MapTypeKeyword
610                | SyntaxKind::MetaKeyword
611                | SyntaxKind::NoneKeyword
612                | SyntaxKind::NullKeyword
613                | SyntaxKind::ObjectKeyword
614                | SyntaxKind::ObjectTypeKeyword
615                | SyntaxKind::OutputKeyword
616                | SyntaxKind::PairTypeKeyword
617                | SyntaxKind::ParameterMetaKeyword
618                | SyntaxKind::RequirementsKeyword
619                | SyntaxKind::RuntimeKeyword
620                | SyntaxKind::ScatterKeyword
621                | SyntaxKind::StringTypeKeyword
622                | SyntaxKind::StructKeyword
623                | SyntaxKind::EnumKeyword
624                | SyntaxKind::TaskKeyword
625                | SyntaxKind::ThenKeyword
626                | SyntaxKind::TrueKeyword
627                | SyntaxKind::VersionKeyword
628                | SyntaxKind::WorkflowKeyword
629        )
630    }
631
632    /// Returns whether the [`SyntaxKind`] is an operator.
633    pub fn is_operator(&self) -> bool {
634        matches!(
635            self,
636            SyntaxKind::Plus
637                | SyntaxKind::Minus
638                | SyntaxKind::Slash
639                | SyntaxKind::Percent
640                | SyntaxKind::Asterisk
641                | SyntaxKind::Exponentiation
642                | SyntaxKind::Equal
643                | SyntaxKind::NotEqual
644                | SyntaxKind::Less
645                | SyntaxKind::LessEqual
646                | SyntaxKind::Greater
647                | SyntaxKind::GreaterEqual
648                | SyntaxKind::LogicalAnd
649                | SyntaxKind::LogicalOr
650                | SyntaxKind::Exclamation
651                | SyntaxKind::Assignment
652                | SyntaxKind::QuestionMark
653                | SyntaxKind::Dot
654                | SyntaxKind::Colon
655        )
656    }
657}
658
659/// Every [`SyntaxKind`] variant.
660pub static ALL_SYNTAX_KIND: &[SyntaxKind] = SyntaxKind::VARIANTS;
661
662impl From<SyntaxKind> for rowan::SyntaxKind {
663    fn from(kind: SyntaxKind) -> Self {
664        rowan::SyntaxKind(kind as u16)
665    }
666}
667
668/// Represents the Workflow Definition Language (WDL).
669#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
670pub struct WorkflowDescriptionLanguage;
671
672impl rowan::Language for WorkflowDescriptionLanguage {
673    type Kind = SyntaxKind;
674
675    fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind {
676        assert!(raw.0 <= SyntaxKind::MAX as u16);
677        unsafe { std::mem::transmute::<u16, SyntaxKind>(raw.0) }
678    }
679
680    fn kind_to_raw(kind: Self::Kind) -> rowan::SyntaxKind {
681        kind.into()
682    }
683}
684
685/// Represents a node in the concrete syntax tree.
686pub type SyntaxNode = rowan::SyntaxNode<WorkflowDescriptionLanguage>;
687/// Represents a token in the concrete syntax tree.
688pub type SyntaxToken = rowan::SyntaxToken<WorkflowDescriptionLanguage>;
689/// Represents an element (node or token) in the concrete syntax tree.
690pub type SyntaxElement = rowan::SyntaxElement<WorkflowDescriptionLanguage>;
691/// Represents node children in the concrete syntax tree.
692pub type SyntaxNodeChildren = rowan::SyntaxNodeChildren<WorkflowDescriptionLanguage>;
693
694/// Constructs a concrete syntax tree from a list of parser events.
695pub fn construct_tree(source: &str, mut events: Vec<Event>) -> SyntaxNode {
696    let mut builder = GreenNodeBuilder::default();
697    let mut ancestors = Vec::new();
698
699    for i in 0..events.len() {
700        match std::mem::replace(&mut events[i], Event::abandoned()) {
701            Event::NodeStarted {
702                kind,
703                forward_parent,
704            } => {
705                // Walk the forward parent chain, if there is one, and push
706                // each forward parent to the ancestors list
707                ancestors.push(kind);
708                let mut idx = i;
709                let mut fp: Option<usize> = forward_parent;
710                while let Some(distance) = fp {
711                    idx += distance;
712                    fp = match std::mem::replace(&mut events[idx], Event::abandoned()) {
713                        Event::NodeStarted {
714                            kind,
715                            forward_parent,
716                        } => {
717                            ancestors.push(kind);
718                            forward_parent
719                        }
720                        _ => unreachable!(),
721                    };
722                }
723
724                // As the current node was pushed first and then its ancestors, walk
725                // the list in reverse to start the "oldest" ancestor first
726                for kind in ancestors.drain(..).rev() {
727                    if kind != SyntaxKind::Abandoned {
728                        builder.start_node(kind.into());
729                    }
730                }
731            }
732            Event::NodeFinished => builder.finish_node(),
733            Event::Token { kind, span } => {
734                builder.token(kind.into(), &source[span.start()..span.end()])
735            }
736        }
737    }
738
739    SyntaxNode::new_root(builder.finish())
740}
741
742/// Represents an untyped concrete syntax tree.
743#[derive(Clone, PartialEq, Eq, Hash)]
744pub struct SyntaxTree(SyntaxNode);
745
746impl SyntaxTree {
747    /// Parses WDL source to produce a syntax tree.
748    ///
749    /// A syntax tree is always returned, even for invalid WDL documents.
750    ///
751    /// Additionally, the list of diagnostics encountered during the parse is
752    /// returned; if the list is empty, the tree is syntactically correct.
753    ///
754    /// However, additional validation is required to ensure the source is
755    /// a valid WDL document.
756    ///
757    /// # Example
758    ///
759    /// ```rust
760    /// # use wdl_grammar::SyntaxTree;
761    /// let (tree, diagnostics) = SyntaxTree::parse("version 1.1");
762    /// assert!(diagnostics.is_empty());
763    /// println!("{tree:#?}");
764    /// ```
765    pub fn parse(source: &str) -> (Self, Vec<Diagnostic>) {
766        let parser = Parser::new(Lexer::new(source));
767        let (events, mut diagnostics) = grammar::document(parser);
768        diagnostics.sort();
769        (Self(construct_tree(source, events)), diagnostics)
770    }
771
772    /// Gets the root syntax node of the tree.
773    pub fn root(&self) -> &SyntaxNode {
774        &self.0
775    }
776
777    /// Gets a copy of the underlying root green node for the tree.
778    pub fn green(&self) -> Cow<'_, GreenNodeData> {
779        self.0.green()
780    }
781
782    /// Converts the tree into a syntax node.
783    pub fn into_syntax(self) -> SyntaxNode {
784        self.0
785    }
786}
787
788impl fmt::Display for SyntaxTree {
789    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
790        self.0.fmt(f)
791    }
792}
793
794impl fmt::Debug for SyntaxTree {
795    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
796        self.0.fmt(f)
797    }
798}
799
800/// An extension trait for [`SyntaxToken`]s.
801pub trait SyntaxTokenExt {
802    /// Gets all of the substantial preceding trivia for an element.
803    fn preceding_trivia(&self) -> impl Iterator<Item = SyntaxToken>;
804
805    /// Get any inline comment directly following an element on the
806    /// same line.
807    fn inline_comment(&self) -> Option<SyntaxToken>;
808}
809
810impl SyntaxTokenExt for SyntaxToken {
811    fn preceding_trivia(&self) -> impl Iterator<Item = SyntaxToken> {
812        let mut tokens = VecDeque::new();
813        let mut cur = self.prev_token();
814        while let Some(token) = cur {
815            cur = token.prev_token();
816            // Stop at first non-trivia
817            if !token.kind().is_trivia() {
818                break;
819            }
820            // Stop if a comment is not on its own line
821            if token.kind() == SyntaxKind::Comment
822                && let Some(prev) = token.prev_token()
823            {
824                if prev.kind() == SyntaxKind::Whitespace {
825                    let has_newlines = prev.text().chars().any(|c| c == '\n');
826                    // If there are newlines in 'prev' then we know
827                    // that the comment is on its own line.
828                    // The comment may still be on its own line if
829                    // 'prev' does not have newlines and nothing comes
830                    // before 'prev'.
831                    if !has_newlines && prev.prev_token().is_some() {
832                        break;
833                    }
834                } else {
835                    // There is something else on this line before the comment.
836                    break;
837                }
838            }
839            // Filter out whitespace that is not substantial
840            match token.kind() {
841                SyntaxKind::Whitespace
842                    if token.text().chars().filter(|c| *c == '\n').count() > 1 =>
843                {
844                    tokens.push_front(token);
845                }
846                SyntaxKind::Comment => {
847                    tokens.push_front(token);
848                }
849                _ => {}
850            }
851        }
852        tokens.into_iter()
853    }
854
855    fn inline_comment(&self) -> Option<SyntaxToken> {
856        let mut next = self.next_token();
857        iter::from_fn(move || {
858            let cur = next.clone()?;
859            next = cur.next_token();
860            Some(cur)
861        })
862        .take_while(|t| {
863            // Stop at non-trivia
864            if !t.kind().is_trivia() {
865                return false;
866            }
867            // Stop on first whitespace containing a newline
868            if t.kind() == SyntaxKind::Whitespace {
869                return !t.text().chars().any(|c| c == '\n');
870            }
871            true
872        })
873        .find(|t| t.kind() == SyntaxKind::Comment)
874    }
875}
876
877#[cfg(test)]
878mod tests {
879    use super::*;
880    use crate::SyntaxTree;
881
882    #[test]
883    fn preceding_comments() {
884        let (tree, diagnostics) = SyntaxTree::parse(
885            "version 1.2
886
887# This comment should not be included
888task foo {} # This comment should not be included
889
890# Some
891# comments
892# are
893# long
894    
895# Others are short
896
897#     and, yet    another
898workflow foo {} # This should not be collected.
899
900# This comment should not be included either.",
901        );
902
903        assert!(diagnostics.is_empty());
904
905        let workflow = tree.root().last_child().unwrap();
906        assert_eq!(workflow.kind(), SyntaxKind::WorkflowDefinitionNode);
907        let token = workflow.first_token().unwrap();
908        let mut trivia = token.preceding_trivia();
909        assert_eq!(trivia.next().unwrap().text(), "\n\n");
910        assert_eq!(trivia.next().unwrap().text(), "# Some");
911        assert_eq!(trivia.next().unwrap().text(), "# comments");
912        assert_eq!(trivia.next().unwrap().text(), "# are");
913        assert_eq!(trivia.next().unwrap().text(), "# long");
914        assert_eq!(trivia.next().unwrap().text(), "\n    \n");
915        assert_eq!(trivia.next().unwrap().text(), "# Others are short");
916        assert_eq!(trivia.next().unwrap().text(), "\n\n");
917        assert_eq!(trivia.next().unwrap().text(), "#     and, yet    another");
918        assert!(trivia.next().is_none());
919    }
920
921    #[test]
922    fn inline_comment() {
923        let (tree, diagnostics) = SyntaxTree::parse(
924            "version 1.2
925
926# This comment should not be included
927task foo {}
928
929# This should not be collected.
930workflow foo {} # Here is a comment that should be collected.
931
932# This comment should not be included either.",
933        );
934
935        assert!(diagnostics.is_empty());
936
937        let workflow = tree.root().last_child().unwrap();
938        assert_eq!(workflow.kind(), SyntaxKind::WorkflowDefinitionNode);
939        let comment = workflow.last_token().unwrap().inline_comment().unwrap();
940        assert_eq!(
941            comment.text(),
942            "# Here is a comment that should be collected."
943        );
944    }
945}