1#![warn(missing_docs)]
27#![warn(rust_2018_idioms)]
28#![warn(rust_2021_compatibility)]
29#![warn(missing_debug_implementations)]
30#![warn(clippy::missing_docs_in_private_items)]
31#![warn(rustdoc::broken_intra_doc_links)]
32
33use std::fmt;
34
35pub use rowan::Direction;
36use rowan::NodeOrToken;
37use v1::CloseBrace;
38use v1::CloseHeredoc;
39use v1::OpenBrace;
40use v1::OpenHeredoc;
41pub use wdl_grammar::Diagnostic;
42pub use wdl_grammar::Label;
43pub use wdl_grammar::Severity;
44pub use wdl_grammar::Span;
45pub use wdl_grammar::SupportedVersion;
46pub use wdl_grammar::SyntaxElement;
47pub use wdl_grammar::SyntaxKind;
48pub use wdl_grammar::SyntaxNode;
49pub use wdl_grammar::SyntaxToken;
50pub use wdl_grammar::SyntaxTokenExt;
51pub use wdl_grammar::SyntaxTree;
52pub use wdl_grammar::WorkflowDescriptionLanguage;
53pub use wdl_grammar::lexer;
54pub use wdl_grammar::version;
55
56pub mod v1;
57
58mod element;
59
60pub use element::*;
61
62pub trait TreeNode: Clone + fmt::Debug + PartialEq + Eq + std::hash::Hash {
66 type Token: TreeToken;
68
69 fn parent(&self) -> Option<Self>;
73
74 fn kind(&self) -> SyntaxKind;
76
77 fn text(&self) -> impl fmt::Display;
81
82 fn span(&self) -> Span;
84
85 fn children(&self) -> impl Iterator<Item = Self>;
87
88 fn children_with_tokens(&self) -> impl Iterator<Item = NodeOrToken<Self, Self::Token>>;
90
91 fn last_token(&self) -> Option<Self::Token>;
93
94 fn descendants(&self) -> impl Iterator<Item = Self>;
96
97 fn ancestors(&self) -> impl Iterator<Item = Self>;
99}
100
101pub trait TreeToken: Clone + fmt::Debug + PartialEq + Eq + std::hash::Hash {
103 type Node: TreeNode;
105
106 fn parent(&self) -> Self::Node;
108
109 fn kind(&self) -> SyntaxKind;
111
112 fn text(&self) -> &str;
114
115 fn span(&self) -> Span;
117}
118
119pub trait AstNode<N: TreeNode>: Sized {
121 fn can_cast(kind: SyntaxKind) -> bool;
123
124 fn cast(inner: N) -> Option<Self>;
126
127 fn inner(&self) -> &N;
129
130 fn kind(&self) -> SyntaxKind {
132 self.inner().kind()
133 }
134
135 fn text<'a>(&'a self) -> impl fmt::Display
140 where
141 N: 'a,
142 {
143 self.inner().text()
144 }
145
146 fn span(&self) -> Span {
148 self.inner().span()
149 }
150
151 fn token<C>(&self) -> Option<C>
153 where
154 C: AstToken<N::Token>,
155 {
156 self.inner()
157 .children_with_tokens()
158 .filter_map(|e| e.into_token())
159 .find_map(|t| C::cast(t))
160 }
161
162 fn tokens<'a, C>(&'a self) -> impl Iterator<Item = C>
164 where
165 C: AstToken<N::Token>,
166 N: 'a,
167 {
168 self.inner()
169 .children_with_tokens()
170 .filter_map(|e| e.into_token().and_then(C::cast))
171 }
172
173 fn last_token<C>(&self) -> Option<C>
179 where
180 C: AstToken<N::Token>,
181 {
182 self.inner().last_token().and_then(C::cast)
183 }
184
185 fn child<C>(&self) -> Option<C>
187 where
188 C: AstNode<N>,
189 {
190 self.inner().children().find_map(C::cast)
191 }
192
193 fn children<'a, C>(&'a self) -> impl Iterator<Item = C>
195 where
196 C: AstNode<N>,
197 N: 'a,
198 {
199 self.inner().children().filter_map(C::cast)
200 }
201
202 fn parent<'a, P>(&self) -> Option<P>
207 where
208 P: AstNode<N>,
209 N: 'a,
210 {
211 P::cast(self.inner().parent()?)
212 }
213
214 fn scope_span<O, C>(&self) -> Option<Span>
220 where
221 O: AstToken<N::Token>,
222 C: AstToken<N::Token>,
223 {
224 let open = self.token::<O>()?.span();
225 let close = self.last_token::<C>()?.span();
226
227 Some(Span::new(open.end(), close.start() - open.end()))
229 }
230
231 fn braced_scope_span(&self) -> Option<Span> {
239 self.scope_span::<OpenBrace<N::Token>, CloseBrace<N::Token>>()
240 }
241
242 fn heredoc_scope_span(&self) -> Option<Span> {
250 self.scope_span::<OpenHeredoc<N::Token>, CloseHeredoc<N::Token>>()
251 }
252
253 fn descendants<'a, D>(&'a self) -> impl Iterator<Item = D>
256 where
257 D: AstNode<N>,
258 N: 'a,
259 {
260 self.inner().descendants().filter_map(|d| D::cast(d))
261 }
262}
263
264pub trait AstToken<T: TreeToken>: Sized {
266 fn can_cast(kind: SyntaxKind) -> bool;
268
269 fn cast(inner: T) -> Option<Self>;
271
272 fn inner(&self) -> &T;
274
275 fn kind(&self) -> SyntaxKind {
277 self.inner().kind()
278 }
279
280 fn text<'a>(&'a self) -> &'a str
282 where
283 T: 'a,
284 {
285 self.inner().text()
286 }
287
288 fn span(&self) -> Span {
290 self.inner().span()
291 }
292
293 fn parent<'a, P>(&self) -> Option<P>
297 where
298 P: AstNode<T::Node>,
299 T: 'a,
300 {
301 P::cast(self.inner().parent())
302 }
303}
304
305pub trait NewRoot<N: TreeNode>: Sized {
308 fn new_root(root: N) -> Self;
311}
312
313impl TreeNode for SyntaxNode {
314 type Token = SyntaxToken;
315
316 fn parent(&self) -> Option<SyntaxNode> {
317 self.parent()
318 }
319
320 fn kind(&self) -> SyntaxKind {
321 self.kind()
322 }
323
324 fn children(&self) -> impl Iterator<Item = Self> {
325 self.children()
326 }
327
328 fn children_with_tokens(&self) -> impl Iterator<Item = NodeOrToken<Self, Self::Token>> {
329 self.children_with_tokens()
330 }
331
332 fn text(&self) -> impl fmt::Display {
333 self.text()
334 }
335
336 fn span(&self) -> Span {
337 let range = self.text_range();
338 let start = usize::from(range.start());
339 Span::new(start, usize::from(range.end()) - start)
340 }
341
342 fn last_token(&self) -> Option<Self::Token> {
343 self.last_token()
344 }
345
346 fn descendants(&self) -> impl Iterator<Item = Self> {
347 self.descendants()
348 }
349
350 fn ancestors(&self) -> impl Iterator<Item = Self> {
351 self.ancestors()
352 }
353}
354
355impl TreeToken for SyntaxToken {
356 type Node = SyntaxNode;
357
358 fn parent(&self) -> SyntaxNode {
359 self.parent().expect("token should have a parent")
360 }
361
362 fn kind(&self) -> SyntaxKind {
363 self.kind()
364 }
365
366 fn text(&self) -> &str {
367 self.text()
368 }
369
370 fn span(&self) -> Span {
371 let range = self.text_range();
372 let start = usize::from(range.start());
373 Span::new(start, usize::from(range.end()) - start)
374 }
375}
376
377#[derive(Clone, Debug, PartialEq, Eq)]
381pub enum Ast<N: TreeNode = SyntaxNode> {
382 Unsupported,
384 V1(v1::Ast<N>),
386}
387
388impl<N: TreeNode> Ast<N> {
389 pub fn as_v1(&self) -> Option<&v1::Ast<N>> {
393 match self {
394 Self::V1(ast) => Some(ast),
395 _ => None,
396 }
397 }
398
399 pub fn into_v1(self) -> Option<v1::Ast<N>> {
401 match self {
402 Self::V1(ast) => Some(ast),
403 _ => None,
404 }
405 }
406
407 pub fn unwrap_v1(self) -> v1::Ast<N> {
413 self.into_v1().expect("the AST is not a V1 AST")
414 }
415}
416
417#[derive(Clone, PartialEq, Eq, Hash)]
422pub struct Document<N: TreeNode = SyntaxNode>(N);
423
424impl<N: TreeNode> AstNode<N> for Document<N> {
425 fn can_cast(kind: SyntaxKind) -> bool {
426 kind == SyntaxKind::RootNode
427 }
428
429 fn cast(inner: N) -> Option<Self> {
430 if Self::can_cast(inner.kind()) {
431 Some(Self(inner))
432 } else {
433 None
434 }
435 }
436
437 fn inner(&self) -> &N {
438 &self.0
439 }
440}
441
442impl Document {
443 pub fn parse(source: &str) -> (Self, Vec<Diagnostic>) {
471 let (tree, diagnostics) = SyntaxTree::parse(source);
472 (
473 Document::cast(tree.into_syntax()).expect("document should cast"),
474 diagnostics,
475 )
476 }
477}
478
479impl<N: TreeNode> Document<N> {
480 pub fn version_statement(&self) -> Option<VersionStatement<N>> {
487 self.child()
488 }
489
490 pub fn ast(&self) -> Ast<N> {
492 self.ast_with_version_fallback(None)
493 }
494
495 pub fn ast_with_version_fallback(&self, fallback_version: Option<SupportedVersion>) -> Ast<N> {
512 let Some(stmt) = self.version_statement() else {
513 return Ast::Unsupported;
514 };
515 let Some(version) = stmt
518 .version()
519 .text()
520 .parse::<SupportedVersion>()
521 .ok()
522 .or(fallback_version)
523 else {
524 return Ast::Unsupported;
525 };
526 match version {
527 SupportedVersion::V1(_) => Ast::V1(v1::Ast(self.0.clone())),
528 _ => Ast::Unsupported,
529 }
530 }
531
532 pub fn morph<U: TreeNode + NewRoot<N>>(self) -> Document<U> {
535 Document(U::new_root(self.0))
536 }
537}
538
539impl fmt::Debug for Document {
540 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
541 self.0.fmt(f)
542 }
543}
544
545#[derive(Clone, Debug, PartialEq, Eq, Hash)]
547pub struct Whitespace<T: TreeToken = SyntaxToken>(T);
548
549impl<T: TreeToken> AstToken<T> for Whitespace<T> {
550 fn can_cast(kind: SyntaxKind) -> bool {
551 kind == SyntaxKind::Whitespace
552 }
553
554 fn cast(inner: T) -> Option<Self> {
555 match inner.kind() {
556 SyntaxKind::Whitespace => Some(Self(inner)),
557 _ => None,
558 }
559 }
560
561 fn inner(&self) -> &T {
562 &self.0
563 }
564}
565
566#[derive(Debug, Clone, PartialEq, Eq, Hash)]
568pub struct Comment<T: TreeToken = SyntaxToken>(T);
569
570impl<T: TreeToken> AstToken<T> for Comment<T> {
571 fn can_cast(kind: SyntaxKind) -> bool {
572 kind == SyntaxKind::Comment
573 }
574
575 fn cast(inner: T) -> Option<Self> {
576 match inner.kind() {
577 SyntaxKind::Comment => Some(Self(inner)),
578 _ => None,
579 }
580 }
581
582 fn inner(&self) -> &T {
583 &self.0
584 }
585}
586
587#[derive(Debug, Clone, PartialEq, Eq, Hash)]
589pub struct VersionStatement<N: TreeNode = SyntaxNode>(N);
590
591impl<N: TreeNode> VersionStatement<N> {
592 pub fn version(&self) -> Version<N::Token> {
594 self.token()
595 .expect("version statement must have a version token")
596 }
597
598 pub fn keyword(&self) -> v1::VersionKeyword<N::Token> {
600 self.token()
601 .expect("version statement must have a version keyword")
602 }
603}
604
605impl<N: TreeNode> AstNode<N> for VersionStatement<N> {
606 fn can_cast(kind: SyntaxKind) -> bool {
607 kind == SyntaxKind::VersionStatementNode
608 }
609
610 fn cast(inner: N) -> Option<Self> {
611 match inner.kind() {
612 SyntaxKind::VersionStatementNode => Some(Self(inner)),
613 _ => None,
614 }
615 }
616
617 fn inner(&self) -> &N {
618 &self.0
619 }
620}
621
622#[derive(Clone, Debug, PartialEq, Eq, Hash)]
624pub struct Version<T: TreeToken = SyntaxToken>(T);
625
626impl<T: TreeToken> AstToken<T> for Version<T> {
627 fn can_cast(kind: SyntaxKind) -> bool {
628 kind == SyntaxKind::Version
629 }
630
631 fn cast(inner: T) -> Option<Self> {
632 match inner.kind() {
633 SyntaxKind::Version => Some(Self(inner)),
634 _ => None,
635 }
636 }
637
638 fn inner(&self) -> &T {
639 &self.0
640 }
641}
642
643#[derive(Debug, Clone, PartialEq, Eq, Hash)]
645pub struct Ident<T: TreeToken = SyntaxToken>(T);
646
647impl<T: TreeToken> Ident<T> {
648 pub fn hashable(&self) -> TokenText<T> {
650 TokenText(self.0.clone())
651 }
652}
653
654impl<T: TreeToken> AstToken<T> for Ident<T> {
655 fn can_cast(kind: SyntaxKind) -> bool {
656 kind == SyntaxKind::Ident
657 }
658
659 fn cast(inner: T) -> Option<Self> {
660 match inner.kind() {
661 SyntaxKind::Ident => Some(Self(inner)),
662 _ => None,
663 }
664 }
665
666 fn inner(&self) -> &T {
667 &self.0
668 }
669}
670
671#[derive(Debug, Clone)]
680pub struct TokenText<T: TreeToken = SyntaxToken>(T);
681
682impl TokenText {
683 pub fn text(&self) -> &str {
685 self.0.text()
686 }
687
688 pub fn span(&self) -> Span {
690 self.0.span()
691 }
692}
693
694impl<T: TreeToken> PartialEq for TokenText<T> {
695 fn eq(&self, other: &Self) -> bool {
696 self.0.text() == other.0.text()
697 }
698}
699
700impl<T: TreeToken> Eq for TokenText<T> {}
701
702impl<T: TreeToken> std::hash::Hash for TokenText<T> {
703 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
704 self.0.text().hash(state);
705 }
706}
707
708impl<T: TreeToken> std::borrow::Borrow<str> for TokenText<T> {
709 fn borrow(&self) -> &str {
710 self.0.text()
711 }
712}