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::SyntaxExt;
48pub use wdl_grammar::SyntaxKind;
49pub use wdl_grammar::SyntaxNode;
50pub use wdl_grammar::SyntaxToken;
51pub use wdl_grammar::SyntaxTokenExt;
52pub use wdl_grammar::SyntaxTree;
53pub use wdl_grammar::WorkflowDescriptionLanguage;
54pub use wdl_grammar::lexer;
55pub use wdl_grammar::version;
56
57pub mod v1;
58
59mod element;
60
61pub use element::*;
62
63pub trait TreeNode: Clone + fmt::Debug + PartialEq + Eq + std::hash::Hash {
67 type Token: TreeToken;
69
70 fn parent(&self) -> Option<Self>;
74
75 fn kind(&self) -> SyntaxKind;
77
78 fn text(&self) -> impl fmt::Display;
82
83 fn span(&self) -> Span;
85
86 fn children(&self) -> impl Iterator<Item = Self>;
88
89 fn children_with_tokens(&self) -> impl Iterator<Item = NodeOrToken<Self, Self::Token>>;
91
92 fn last_token(&self) -> Option<Self::Token>;
94
95 fn descendants(&self) -> impl Iterator<Item = Self>;
97
98 fn ancestors(&self) -> impl Iterator<Item = Self>;
100}
101
102pub trait TreeToken: Clone + fmt::Debug + PartialEq + Eq + std::hash::Hash {
104 type Node: TreeNode;
106
107 fn parent(&self) -> Self::Node;
109
110 fn kind(&self) -> SyntaxKind;
112
113 fn text(&self) -> &str;
115
116 fn span(&self) -> Span;
118}
119
120pub trait AstNode<N: TreeNode>: Sized {
122 fn can_cast(kind: SyntaxKind) -> bool;
124
125 fn cast(inner: N) -> Option<Self>;
127
128 fn inner(&self) -> &N;
130
131 fn kind(&self) -> SyntaxKind {
133 self.inner().kind()
134 }
135
136 fn text<'a>(&'a self) -> impl fmt::Display
141 where
142 N: 'a,
143 {
144 self.inner().text()
145 }
146
147 fn span(&self) -> Span {
149 self.inner().span()
150 }
151
152 fn token<C>(&self) -> Option<C>
154 where
155 C: AstToken<N::Token>,
156 {
157 self.inner()
158 .children_with_tokens()
159 .filter_map(|e| e.into_token())
160 .find_map(|t| C::cast(t))
161 }
162
163 fn tokens<'a, C>(&'a self) -> impl Iterator<Item = C>
165 where
166 C: AstToken<N::Token>,
167 N: 'a,
168 {
169 self.inner()
170 .children_with_tokens()
171 .filter_map(|e| e.into_token().and_then(C::cast))
172 }
173
174 fn last_token<C>(&self) -> Option<C>
180 where
181 C: AstToken<N::Token>,
182 {
183 self.inner().last_token().and_then(C::cast)
184 }
185
186 fn child<C>(&self) -> Option<C>
188 where
189 C: AstNode<N>,
190 {
191 self.inner().children().find_map(C::cast)
192 }
193
194 fn children<'a, C>(&'a self) -> impl Iterator<Item = C>
196 where
197 C: AstNode<N>,
198 N: 'a,
199 {
200 self.inner().children().filter_map(C::cast)
201 }
202
203 fn parent<'a, P>(&self) -> Option<P>
208 where
209 P: AstNode<N>,
210 N: 'a,
211 {
212 P::cast(self.inner().parent()?)
213 }
214
215 fn scope_span<O, C>(&self) -> Option<Span>
221 where
222 O: AstToken<N::Token>,
223 C: AstToken<N::Token>,
224 {
225 let open = self.token::<O>()?.span();
226 let close = self.last_token::<C>()?.span();
227
228 Some(Span::new(open.end(), close.start() - open.end()))
230 }
231
232 fn braced_scope_span(&self) -> Option<Span> {
240 self.scope_span::<OpenBrace<N::Token>, CloseBrace<N::Token>>()
241 }
242
243 fn heredoc_scope_span(&self) -> Option<Span> {
251 self.scope_span::<OpenHeredoc<N::Token>, CloseHeredoc<N::Token>>()
252 }
253
254 fn descendants<'a, D>(&'a self) -> impl Iterator<Item = D>
257 where
258 D: AstNode<N>,
259 N: 'a,
260 {
261 self.inner().descendants().filter_map(|d| D::cast(d))
262 }
263}
264
265pub trait AstToken<T: TreeToken>: Sized {
267 fn can_cast(kind: SyntaxKind) -> bool;
269
270 fn cast(inner: T) -> Option<Self>;
272
273 fn inner(&self) -> &T;
275
276 fn kind(&self) -> SyntaxKind {
278 self.inner().kind()
279 }
280
281 fn text<'a>(&'a self) -> &'a str
283 where
284 T: 'a,
285 {
286 self.inner().text()
287 }
288
289 fn span(&self) -> Span {
291 self.inner().span()
292 }
293
294 fn parent<'a, P>(&self) -> Option<P>
298 where
299 P: AstNode<T::Node>,
300 T: 'a,
301 {
302 P::cast(self.inner().parent())
303 }
304}
305
306pub trait NewRoot<N: TreeNode>: Sized {
309 fn new_root(root: N) -> Self;
312}
313
314impl TreeNode for SyntaxNode {
315 type Token = SyntaxToken;
316
317 fn parent(&self) -> Option<SyntaxNode> {
318 self.parent()
319 }
320
321 fn kind(&self) -> SyntaxKind {
322 self.kind()
323 }
324
325 fn children(&self) -> impl Iterator<Item = Self> {
326 self.children()
327 }
328
329 fn children_with_tokens(&self) -> impl Iterator<Item = NodeOrToken<Self, Self::Token>> {
330 self.children_with_tokens()
331 }
332
333 fn text(&self) -> impl fmt::Display {
334 self.text()
335 }
336
337 fn span(&self) -> Span {
338 let range = self.text_range();
339 let start = usize::from(range.start());
340 Span::new(start, usize::from(range.end()) - start)
341 }
342
343 fn last_token(&self) -> Option<Self::Token> {
344 self.last_token()
345 }
346
347 fn descendants(&self) -> impl Iterator<Item = Self> {
348 self.descendants()
349 }
350
351 fn ancestors(&self) -> impl Iterator<Item = Self> {
352 self.ancestors()
353 }
354}
355
356impl TreeToken for SyntaxToken {
357 type Node = SyntaxNode;
358
359 fn parent(&self) -> SyntaxNode {
360 self.parent().expect("token should have a parent")
361 }
362
363 fn kind(&self) -> SyntaxKind {
364 self.kind()
365 }
366
367 fn text(&self) -> &str {
368 self.text()
369 }
370
371 fn span(&self) -> Span {
372 let range = self.text_range();
373 let start = usize::from(range.start());
374 Span::new(start, usize::from(range.end()) - start)
375 }
376}
377
378#[derive(Clone, Debug, PartialEq, Eq)]
382pub enum Ast<N: TreeNode = SyntaxNode> {
383 Unsupported,
385 V1(v1::Ast<N>),
387}
388
389impl<N: TreeNode> Ast<N> {
390 pub fn as_v1(&self) -> Option<&v1::Ast<N>> {
394 match self {
395 Self::V1(ast) => Some(ast),
396 _ => None,
397 }
398 }
399
400 pub fn into_v1(self) -> Option<v1::Ast<N>> {
402 match self {
403 Self::V1(ast) => Some(ast),
404 _ => None,
405 }
406 }
407
408 pub fn unwrap_v1(self) -> v1::Ast<N> {
414 self.into_v1().expect("the AST is not a V1 AST")
415 }
416}
417
418#[derive(Clone, PartialEq, Eq, Hash)]
423pub struct Document<N: TreeNode = SyntaxNode>(N);
424
425impl<N: TreeNode> AstNode<N> for Document<N> {
426 fn can_cast(kind: SyntaxKind) -> bool {
427 kind == SyntaxKind::RootNode
428 }
429
430 fn cast(inner: N) -> Option<Self> {
431 if Self::can_cast(inner.kind()) {
432 Some(Self(inner))
433 } else {
434 None
435 }
436 }
437
438 fn inner(&self) -> &N {
439 &self.0
440 }
441}
442
443impl Document {
444 pub fn parse(source: &str) -> (Self, Vec<Diagnostic>) {
472 let (tree, diagnostics) = SyntaxTree::parse(source);
473 (
474 Document::cast(tree.into_syntax()).expect("document should cast"),
475 diagnostics,
476 )
477 }
478}
479
480impl<N: TreeNode> Document<N> {
481 pub fn version_statement(&self) -> Option<VersionStatement<N>> {
488 self.child()
489 }
490
491 pub fn ast(&self) -> Ast<N> {
493 self.version_statement()
494 .as_ref()
495 .and_then(|s| s.version().text().parse::<SupportedVersion>().ok())
496 .map(|v| match v {
497 SupportedVersion::V1(_) => Ast::V1(v1::Ast(self.0.clone())),
498 _ => Ast::Unsupported,
499 })
500 .unwrap_or(Ast::Unsupported)
501 }
502
503 pub fn morph<U: TreeNode + NewRoot<N>>(self) -> Document<U> {
506 Document(U::new_root(self.0))
507 }
508}
509
510impl fmt::Debug for Document {
511 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
512 self.0.fmt(f)
513 }
514}
515
516#[derive(Clone, Debug, PartialEq, Eq, Hash)]
518pub struct Whitespace<T: TreeToken = SyntaxToken>(T);
519
520impl<T: TreeToken> AstToken<T> for Whitespace<T> {
521 fn can_cast(kind: SyntaxKind) -> bool {
522 kind == SyntaxKind::Whitespace
523 }
524
525 fn cast(inner: T) -> Option<Self> {
526 match inner.kind() {
527 SyntaxKind::Whitespace => Some(Self(inner)),
528 _ => None,
529 }
530 }
531
532 fn inner(&self) -> &T {
533 &self.0
534 }
535}
536
537#[derive(Debug, Clone, PartialEq, Eq, Hash)]
539pub struct Comment<T: TreeToken = SyntaxToken>(T);
540
541impl<T: TreeToken> AstToken<T> for Comment<T> {
542 fn can_cast(kind: SyntaxKind) -> bool {
543 kind == SyntaxKind::Comment
544 }
545
546 fn cast(inner: T) -> Option<Self> {
547 match inner.kind() {
548 SyntaxKind::Comment => Some(Self(inner)),
549 _ => None,
550 }
551 }
552
553 fn inner(&self) -> &T {
554 &self.0
555 }
556}
557
558#[derive(Debug, Clone, PartialEq, Eq, Hash)]
560pub struct VersionStatement<N: TreeNode = SyntaxNode>(N);
561
562impl<N: TreeNode> VersionStatement<N> {
563 pub fn version(&self) -> Version<N::Token> {
565 self.token()
566 .expect("version statement must have a version token")
567 }
568
569 pub fn keyword(&self) -> v1::VersionKeyword<N::Token> {
571 self.token()
572 .expect("version statement must have a version keyword")
573 }
574}
575
576impl<N: TreeNode> AstNode<N> for VersionStatement<N> {
577 fn can_cast(kind: SyntaxKind) -> bool {
578 kind == SyntaxKind::VersionStatementNode
579 }
580
581 fn cast(inner: N) -> Option<Self> {
582 match inner.kind() {
583 SyntaxKind::VersionStatementNode => Some(Self(inner)),
584 _ => None,
585 }
586 }
587
588 fn inner(&self) -> &N {
589 &self.0
590 }
591}
592
593#[derive(Clone, Debug, PartialEq, Eq, Hash)]
595pub struct Version<T: TreeToken = SyntaxToken>(T);
596
597impl<T: TreeToken> AstToken<T> for Version<T> {
598 fn can_cast(kind: SyntaxKind) -> bool {
599 kind == SyntaxKind::Version
600 }
601
602 fn cast(inner: T) -> Option<Self> {
603 match inner.kind() {
604 SyntaxKind::Version => Some(Self(inner)),
605 _ => None,
606 }
607 }
608
609 fn inner(&self) -> &T {
610 &self.0
611 }
612}
613
614#[derive(Debug, Clone, PartialEq, Eq, Hash)]
616pub struct Ident<T: TreeToken = SyntaxToken>(T);
617
618impl<T: TreeToken> Ident<T> {
619 pub fn hashable(&self) -> TokenText<T> {
621 TokenText(self.0.clone())
622 }
623}
624
625impl<T: TreeToken> AstToken<T> for Ident<T> {
626 fn can_cast(kind: SyntaxKind) -> bool {
627 kind == SyntaxKind::Ident
628 }
629
630 fn cast(inner: T) -> Option<Self> {
631 match inner.kind() {
632 SyntaxKind::Ident => Some(Self(inner)),
633 _ => None,
634 }
635 }
636
637 fn inner(&self) -> &T {
638 &self.0
639 }
640}
641
642#[derive(Debug, Clone)]
651pub struct TokenText<T: TreeToken = SyntaxToken>(T);
652
653impl TokenText {
654 pub fn text(&self) -> &str {
656 self.0.text()
657 }
658
659 pub fn span(&self) -> Span {
661 self.0.span()
662 }
663}
664
665impl<T: TreeToken> PartialEq for TokenText<T> {
666 fn eq(&self, other: &Self) -> bool {
667 self.0.text() == other.0.text()
668 }
669}
670
671impl<T: TreeToken> Eq for TokenText<T> {}
672
673impl<T: TreeToken> std::hash::Hash for TokenText<T> {
674 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
675 self.0.text().hash(state);
676 }
677}
678
679impl<T: TreeToken> std::borrow::Borrow<str> for TokenText<T> {
680 fn borrow(&self) -> &str {
681 self.0.text()
682 }
683}