1use std::fmt;
4
5use rowan::NodeOrToken;
6use wdl_grammar::SupportedVersion;
7use wdl_grammar::version::V1;
8
9use super::BoundDecl;
10use super::Expr;
11use super::InputSection;
12use super::LiteralBoolean;
13use super::LiteralFloat;
14use super::LiteralInteger;
15use super::LiteralString;
16use super::MetadataSection;
17use super::MetadataValue;
18use super::OutputSection;
19use super::ParameterMetadataSection;
20use crate::AstNode;
21use crate::AstToken;
22use crate::Ident;
23use crate::SyntaxKind;
24use crate::SyntaxNode;
25use crate::TreeNode;
26use crate::v1::display::write_input_section;
27use crate::v1::display::write_output_section;
28
29pub const WORKFLOW_HINT_ALLOW_NESTED_INPUTS: &str = "allow_nested_inputs";
32
33pub const WORKFLOW_HINT_ALLOW_NESTED_INPUTS_ALIAS: &str = "allowNestedInputs";
37
38pub const WORKFLOW_HINT_KEYS: &[(&str, &str)] = &[(
40 WORKFLOW_HINT_ALLOW_NESTED_INPUTS,
41 "If `true`, allows nested input objects for the workflow.",
42)];
43
44#[derive(Clone, Debug, PartialEq, Eq)]
46pub struct WorkflowDefinition<N: TreeNode = SyntaxNode>(N);
47
48impl<N: TreeNode> WorkflowDefinition<N> {
49 pub fn name(&self) -> Ident<N::Token> {
51 self.token().expect("workflow should have a name")
52 }
53
54 pub fn items(&self) -> impl Iterator<Item = WorkflowItem<N>> + use<'_, N> {
56 WorkflowItem::children(&self.0)
57 }
58
59 pub fn input(&self) -> Option<InputSection<N>> {
61 self.child()
62 }
63
64 pub fn output(&self) -> Option<OutputSection<N>> {
66 self.child()
67 }
68
69 pub fn statements(&self) -> impl Iterator<Item = WorkflowStatement<N>> + use<'_, N> {
71 WorkflowStatement::children(&self.0)
72 }
73
74 pub fn metadata(&self) -> Option<MetadataSection<N>> {
76 self.child()
77 }
78
79 pub fn parameter_metadata(&self) -> Option<ParameterMetadataSection<N>> {
81 self.child()
82 }
83
84 pub fn hints(&self) -> Option<WorkflowHintsSection<N>> {
86 self.child()
87 }
88
89 pub fn declarations(&self) -> impl Iterator<Item = BoundDecl<N>> + use<'_, N> {
91 self.children()
92 }
93
94 pub fn allows_nested_inputs(&self, version: SupportedVersion) -> bool {
96 match version {
97 SupportedVersion::V1(V1::Zero) => return true,
98 SupportedVersion::V1(V1::One) => {
99 }
101 SupportedVersion::V1(V1::Two) => {
102 let allow = self.hints().and_then(|s| {
104 s.items().find_map(|i| {
105 let name = i.name();
106 if name.text() == WORKFLOW_HINT_ALLOW_NESTED_INPUTS
107 || name.text() == WORKFLOW_HINT_ALLOW_NESTED_INPUTS_ALIAS
108 {
109 match i.value() {
110 WorkflowHintsItemValue::Boolean(v) => Some(v.value()),
111 _ => None,
112 }
113 } else {
114 None
115 }
116 })
117 });
118
119 if let Some(allow) = allow {
120 return allow;
121 }
122
123 }
125 _ => return false,
126 }
127
128 self.metadata()
130 .and_then(|s| {
131 s.items().find_map(|i| {
132 if i.name().text() == WORKFLOW_HINT_ALLOW_NESTED_INPUTS_ALIAS {
133 match i.value() {
134 MetadataValue::Boolean(v) => Some(v.value()),
135 _ => None,
136 }
137 } else {
138 None
139 }
140 })
141 })
142 .unwrap_or(false)
143 }
144
145 pub fn markdown_description(&self, f: &mut impl fmt::Write) -> fmt::Result {
147 writeln!(f, "```wdl\nworkflow {}\n```\n---", self.name().text())?;
148
149 if let Some(meta) = self.metadata()
150 && let Some(desc) = meta.items().find(|i| i.name().text() == "description")
151 && let MetadataValue::String(s) = desc.value()
152 && let Some(text) = s.text()
153 {
154 writeln!(f, "# {}\n", text.text())?;
155 }
156
157 write_input_section(f, self.input().as_ref(), self.parameter_metadata().as_ref())?;
158 write_output_section(
159 f,
160 self.output().as_ref(),
161 self.parameter_metadata().as_ref(),
162 )?;
163
164 Ok(())
165 }
166}
167
168impl<N: TreeNode> AstNode<N> for WorkflowDefinition<N> {
169 fn can_cast(kind: SyntaxKind) -> bool {
170 kind == SyntaxKind::WorkflowDefinitionNode
171 }
172
173 fn cast(inner: N) -> Option<Self> {
174 match inner.kind() {
175 SyntaxKind::WorkflowDefinitionNode => Some(Self(inner)),
176 _ => None,
177 }
178 }
179
180 fn inner(&self) -> &N {
181 &self.0
182 }
183}
184
185#[derive(Clone, Debug, PartialEq, Eq)]
187pub enum WorkflowItem<N: TreeNode = SyntaxNode> {
188 Input(InputSection<N>),
190 Output(OutputSection<N>),
192 Conditional(ConditionalStatement<N>),
194 Scatter(ScatterStatement<N>),
196 Call(CallStatement<N>),
198 Metadata(MetadataSection<N>),
200 ParameterMetadata(ParameterMetadataSection<N>),
202 Hints(WorkflowHintsSection<N>),
204 Declaration(BoundDecl<N>),
206}
207
208impl<N: TreeNode> WorkflowItem<N> {
209 pub fn can_cast(kind: SyntaxKind) -> bool {
212 matches!(
213 kind,
214 SyntaxKind::InputSectionNode
215 | SyntaxKind::OutputSectionNode
216 | SyntaxKind::ConditionalStatementNode
217 | SyntaxKind::ScatterStatementNode
218 | SyntaxKind::CallStatementNode
219 | SyntaxKind::MetadataSectionNode
220 | SyntaxKind::ParameterMetadataSectionNode
221 | SyntaxKind::WorkflowHintsSectionNode
222 | SyntaxKind::BoundDeclNode
223 )
224 }
225
226 pub fn cast(inner: N) -> Option<Self> {
230 match inner.kind() {
231 SyntaxKind::InputSectionNode => Some(Self::Input(
232 InputSection::cast(inner).expect("input section to cast"),
233 )),
234 SyntaxKind::OutputSectionNode => Some(Self::Output(
235 OutputSection::cast(inner).expect("output section to cast"),
236 )),
237 SyntaxKind::ConditionalStatementNode => Some(Self::Conditional(
238 ConditionalStatement::cast(inner).expect("conditional statement to cast"),
239 )),
240 SyntaxKind::ScatterStatementNode => Some(Self::Scatter(
241 ScatterStatement::cast(inner).expect("scatter statement to cast"),
242 )),
243 SyntaxKind::CallStatementNode => Some(Self::Call(
244 CallStatement::cast(inner).expect("call statement to cast"),
245 )),
246 SyntaxKind::MetadataSectionNode => Some(Self::Metadata(
247 MetadataSection::cast(inner).expect("metadata section to cast"),
248 )),
249 SyntaxKind::ParameterMetadataSectionNode => Some(Self::ParameterMetadata(
250 ParameterMetadataSection::cast(inner).expect("parameter metadata section to cast"),
251 )),
252 SyntaxKind::WorkflowHintsSectionNode => Some(Self::Hints(
253 WorkflowHintsSection::cast(inner).expect("workflow hints section to cast"),
254 )),
255 SyntaxKind::BoundDeclNode => Some(Self::Declaration(
256 BoundDecl::cast(inner).expect("bound decl to cast"),
257 )),
258 _ => None,
259 }
260 }
261
262 pub fn inner(&self) -> &N {
264 match self {
265 Self::Input(element) => element.inner(),
266 Self::Output(element) => element.inner(),
267 Self::Conditional(element) => element.inner(),
268 Self::Scatter(element) => element.inner(),
269 Self::Call(element) => element.inner(),
270 Self::Metadata(element) => element.inner(),
271 Self::ParameterMetadata(element) => element.inner(),
272 Self::Hints(element) => element.inner(),
273 Self::Declaration(element) => element.inner(),
274 }
275 }
276
277 pub fn as_input_section(&self) -> Option<&InputSection<N>> {
283 match self {
284 Self::Input(s) => Some(s),
285 _ => None,
286 }
287 }
288
289 pub fn into_input_section(self) -> Option<InputSection<N>> {
295 match self {
296 Self::Input(s) => Some(s),
297 _ => None,
298 }
299 }
300
301 pub fn as_output_section(&self) -> Option<&OutputSection<N>> {
307 match self {
308 Self::Output(s) => Some(s),
309 _ => None,
310 }
311 }
312
313 pub fn into_output_section(self) -> Option<OutputSection<N>> {
319 match self {
320 Self::Output(s) => Some(s),
321 _ => None,
322 }
323 }
324
325 pub fn as_conditional(&self) -> Option<&ConditionalStatement<N>> {
331 match self {
332 Self::Conditional(s) => Some(s),
333 _ => None,
334 }
335 }
336
337 pub fn into_conditional(self) -> Option<ConditionalStatement<N>> {
344 match self {
345 Self::Conditional(s) => Some(s),
346 _ => None,
347 }
348 }
349
350 pub fn as_scatter(&self) -> Option<&ScatterStatement<N>> {
356 match self {
357 Self::Scatter(s) => Some(s),
358 _ => None,
359 }
360 }
361
362 pub fn into_scatter(self) -> Option<ScatterStatement<N>> {
369 match self {
370 Self::Scatter(s) => Some(s),
371 _ => None,
372 }
373 }
374
375 pub fn as_call(&self) -> Option<&CallStatement<N>> {
381 match self {
382 Self::Call(s) => Some(s),
383 _ => None,
384 }
385 }
386
387 pub fn into_call(self) -> Option<CallStatement<N>> {
393 match self {
394 Self::Call(s) => Some(s),
395 _ => None,
396 }
397 }
398
399 pub fn as_metadata_section(&self) -> Option<&MetadataSection<N>> {
405 match self {
406 Self::Metadata(s) => Some(s),
407 _ => None,
408 }
409 }
410
411 pub fn into_metadata_section(self) -> Option<MetadataSection<N>> {
417 match self {
418 Self::Metadata(s) => Some(s),
419 _ => None,
420 }
421 }
422
423 pub fn as_parameter_metadata_section(&self) -> Option<&ParameterMetadataSection<N>> {
430 match self {
431 Self::ParameterMetadata(s) => Some(s),
432 _ => None,
433 }
434 }
435
436 pub fn into_parameter_metadata_section(self) -> Option<ParameterMetadataSection<N>> {
443 match self {
444 Self::ParameterMetadata(s) => Some(s),
445 _ => None,
446 }
447 }
448
449 pub fn as_hints_section(&self) -> Option<&WorkflowHintsSection<N>> {
455 match self {
456 Self::Hints(s) => Some(s),
457 _ => None,
458 }
459 }
460
461 pub fn into_hints_section(self) -> Option<WorkflowHintsSection<N>> {
468 match self {
469 Self::Hints(s) => Some(s),
470 _ => None,
471 }
472 }
473
474 pub fn as_declaration(&self) -> Option<&BoundDecl<N>> {
480 match self {
481 Self::Declaration(d) => Some(d),
482 _ => None,
483 }
484 }
485
486 pub fn into_declaration(self) -> Option<BoundDecl<N>> {
492 match self {
493 Self::Declaration(d) => Some(d),
494 _ => None,
495 }
496 }
497
498 pub fn child(node: &N) -> Option<Self> {
500 node.children().find_map(Self::cast)
501 }
502
503 pub fn children(node: &N) -> impl Iterator<Item = Self> + use<'_, N> {
505 node.children().filter_map(Self::cast)
506 }
507}
508
509#[derive(Clone, Debug, PartialEq, Eq)]
511pub enum WorkflowStatement<N: TreeNode = SyntaxNode> {
512 Conditional(ConditionalStatement<N>),
514 Scatter(ScatterStatement<N>),
516 Call(CallStatement<N>),
518 Declaration(BoundDecl<N>),
520}
521
522impl<N: TreeNode> WorkflowStatement<N> {
523 pub fn can_cast(kind: SyntaxKind) -> bool {
526 matches!(
527 kind,
528 SyntaxKind::ConditionalStatementNode
529 | SyntaxKind::ScatterStatementNode
530 | SyntaxKind::CallStatementNode
531 | SyntaxKind::BoundDeclNode
532 )
533 }
534
535 pub fn cast(inner: N) -> Option<Self> {
539 match inner.kind() {
540 SyntaxKind::ConditionalStatementNode => Some(Self::Conditional(
541 ConditionalStatement::cast(inner).expect("conditional statement to cast"),
542 )),
543 SyntaxKind::ScatterStatementNode => Some(Self::Scatter(
544 ScatterStatement::cast(inner).expect("scatter statement to cast"),
545 )),
546 SyntaxKind::CallStatementNode => Some(Self::Call(
547 CallStatement::cast(inner).expect("call statement to cast"),
548 )),
549 SyntaxKind::BoundDeclNode => Some(Self::Declaration(
550 BoundDecl::cast(inner).expect("bound decl to cast"),
551 )),
552 _ => None,
553 }
554 }
555
556 pub fn inner(&self) -> &N {
558 match self {
559 Self::Conditional(s) => s.inner(),
560 Self::Scatter(s) => s.inner(),
561 Self::Call(s) => s.inner(),
562 Self::Declaration(s) => s.inner(),
563 }
564 }
565
566 pub fn as_conditional(&self) -> Option<&ConditionalStatement<N>> {
572 match self {
573 Self::Conditional(s) => Some(s),
574 _ => None,
575 }
576 }
577
578 pub fn into_conditional(self) -> Option<ConditionalStatement<N>> {
585 match self {
586 Self::Conditional(s) => Some(s),
587 _ => None,
588 }
589 }
590
591 pub fn unwrap_conditional(self) -> ConditionalStatement<N> {
597 match self {
598 Self::Conditional(s) => s,
599 _ => panic!("not a conditional statement"),
600 }
601 }
602
603 pub fn as_scatter(&self) -> Option<&ScatterStatement<N>> {
609 match self {
610 Self::Scatter(s) => Some(s),
611 _ => None,
612 }
613 }
614
615 pub fn into_scatter(self) -> Option<ScatterStatement<N>> {
622 match self {
623 Self::Scatter(s) => Some(s),
624 _ => None,
625 }
626 }
627
628 pub fn unwrap_scatter(self) -> ScatterStatement<N> {
634 match self {
635 Self::Scatter(s) => s,
636 _ => panic!("not a scatter statement"),
637 }
638 }
639
640 pub fn as_call(&self) -> Option<&CallStatement<N>> {
646 match self {
647 Self::Call(s) => Some(s),
648 _ => None,
649 }
650 }
651
652 pub fn into_call(self) -> Option<CallStatement<N>> {
659 match self {
660 Self::Call(s) => Some(s),
661 _ => None,
662 }
663 }
664
665 pub fn unwrap_call(self) -> CallStatement<N> {
671 match self {
672 Self::Call(s) => s,
673 _ => panic!("not a call statement"),
674 }
675 }
676
677 pub fn as_declaration(&self) -> Option<&BoundDecl<N>> {
683 match self {
684 Self::Declaration(d) => Some(d),
685 _ => None,
686 }
687 }
688
689 pub fn into_declaration(self) -> Option<BoundDecl<N>> {
696 match self {
697 Self::Declaration(d) => Some(d),
698 _ => None,
699 }
700 }
701
702 pub fn unwrap_declaration(self) -> BoundDecl<N> {
708 match self {
709 Self::Declaration(d) => d,
710 _ => panic!("not a bound declaration"),
711 }
712 }
713
714 pub fn child(node: &N) -> Option<Self> {
716 node.children().find_map(Self::cast)
717 }
718
719 pub fn children(node: &N) -> impl Iterator<Item = Self> + use<'_, N> {
721 node.children().filter_map(Self::cast)
722 }
723}
724
725#[derive(Clone, Debug, PartialEq, Eq)]
727pub struct ConditionalStatement<N: TreeNode = SyntaxNode>(N);
728
729impl<N: TreeNode> ConditionalStatement<N> {
730 pub fn expr(&self) -> Expr<N> {
732 Expr::child(&self.0).expect("expected a conditional expression")
733 }
734
735 pub fn statements(&self) -> impl Iterator<Item = WorkflowStatement<N>> + use<'_, N> {
737 WorkflowStatement::children(&self.0)
738 }
739}
740
741impl<N: TreeNode> AstNode<N> for ConditionalStatement<N> {
742 fn can_cast(kind: SyntaxKind) -> bool {
743 kind == SyntaxKind::ConditionalStatementNode
744 }
745
746 fn cast(inner: N) -> Option<Self> {
747 match inner.kind() {
748 SyntaxKind::ConditionalStatementNode => Some(Self(inner)),
749 _ => None,
750 }
751 }
752
753 fn inner(&self) -> &N {
754 &self.0
755 }
756}
757
758#[derive(Clone, Debug, PartialEq, Eq)]
760pub struct ScatterStatement<N: TreeNode = SyntaxNode>(N);
761
762impl<N: TreeNode> ScatterStatement<N> {
763 pub fn variable(&self) -> Ident<N::Token> {
765 self.token()
766 .expect("expected a scatter variable identifier")
767 }
768
769 pub fn expr(&self) -> Expr<N> {
771 Expr::child(&self.0).expect("expected a scatter expression")
772 }
773
774 pub fn statements(&self) -> impl Iterator<Item = WorkflowStatement<N>> + use<'_, N> {
776 WorkflowStatement::children(&self.0)
777 }
778}
779
780impl<N: TreeNode> AstNode<N> for ScatterStatement<N> {
781 fn can_cast(kind: SyntaxKind) -> bool {
782 kind == SyntaxKind::ScatterStatementNode
783 }
784
785 fn cast(inner: N) -> Option<Self> {
786 match inner.kind() {
787 SyntaxKind::ScatterStatementNode => Some(Self(inner)),
788 _ => None,
789 }
790 }
791
792 fn inner(&self) -> &N {
793 &self.0
794 }
795}
796
797#[derive(Clone, Debug, PartialEq, Eq)]
799pub struct CallStatement<N: TreeNode = SyntaxNode>(N);
800
801impl<N: TreeNode> CallStatement<N> {
802 pub fn target(&self) -> CallTarget<N> {
804 self.child().expect("expected a call target")
805 }
806
807 pub fn alias(&self) -> Option<CallAlias<N>> {
809 self.child()
810 }
811
812 pub fn after(&self) -> impl Iterator<Item = CallAfter<N>> + use<'_, N> {
814 self.children()
815 }
816
817 pub fn inputs(&self) -> impl Iterator<Item = CallInputItem<N>> + use<'_, N> {
819 self.children()
820 }
821}
822
823impl<N: TreeNode> AstNode<N> for CallStatement<N> {
824 fn can_cast(kind: SyntaxKind) -> bool {
825 kind == SyntaxKind::CallStatementNode
826 }
827
828 fn cast(inner: N) -> Option<Self> {
829 match inner.kind() {
830 SyntaxKind::CallStatementNode => Some(Self(inner)),
831 _ => None,
832 }
833 }
834
835 fn inner(&self) -> &N {
836 &self.0
837 }
838}
839
840#[derive(Clone, Debug, PartialEq, Eq)]
842pub struct CallTarget<N: TreeNode = SyntaxNode>(N);
843
844impl<N: TreeNode> CallTarget<N> {
845 pub fn names(&self) -> impl Iterator<Item = Ident<N::Token>> + use<'_, N> {
850 self.0
851 .children_with_tokens()
852 .filter_map(NodeOrToken::into_token)
853 .filter_map(Ident::cast)
854 }
855}
856
857impl<N: TreeNode> AstNode<N> for CallTarget<N> {
858 fn can_cast(kind: SyntaxKind) -> bool {
859 kind == SyntaxKind::CallTargetNode
860 }
861
862 fn cast(inner: N) -> Option<Self> {
863 match inner.kind() {
864 SyntaxKind::CallTargetNode => Some(Self(inner)),
865 _ => None,
866 }
867 }
868
869 fn inner(&self) -> &N {
870 &self.0
871 }
872}
873
874#[derive(Clone, Debug, PartialEq, Eq)]
876pub struct CallAlias<N: TreeNode = SyntaxNode>(N);
877
878impl<N: TreeNode> CallAlias<N> {
879 pub fn name(&self) -> Ident<N::Token> {
881 self.token().expect("expected an alias identifier")
882 }
883}
884
885impl<N: TreeNode> AstNode<N> for CallAlias<N> {
886 fn can_cast(kind: SyntaxKind) -> bool {
887 kind == SyntaxKind::CallAliasNode
888 }
889
890 fn cast(inner: N) -> Option<Self> {
891 match inner.kind() {
892 SyntaxKind::CallAliasNode => Some(Self(inner)),
893 _ => None,
894 }
895 }
896
897 fn inner(&self) -> &N {
898 &self.0
899 }
900}
901
902#[derive(Clone, Debug, PartialEq, Eq)]
904pub struct CallAfter<N: TreeNode = SyntaxNode>(N);
905
906impl<N: TreeNode> CallAfter<N> {
907 pub fn name(&self) -> Ident<N::Token> {
909 self.token().expect("expected an after identifier")
910 }
911}
912
913impl<N: TreeNode> AstNode<N> for CallAfter<N> {
914 fn can_cast(kind: SyntaxKind) -> bool {
915 kind == SyntaxKind::CallAfterNode
916 }
917
918 fn cast(inner: N) -> Option<Self> {
919 match inner.kind() {
920 SyntaxKind::CallAfterNode => Some(Self(inner)),
921 _ => None,
922 }
923 }
924
925 fn inner(&self) -> &N {
926 &self.0
927 }
928}
929
930#[derive(Clone, Debug, PartialEq, Eq)]
932pub struct CallInputItem<N: TreeNode = SyntaxNode>(N);
933
934impl<N: TreeNode> CallInputItem<N> {
935 pub fn name(&self) -> Ident<N::Token> {
937 self.token().expect("expected an input name")
938 }
939
940 pub fn expr(&self) -> Option<Expr<N>> {
942 Expr::child(&self.0)
943 }
944
945 pub fn parent(&self) -> CallStatement<N> {
947 <Self as AstNode<N>>::parent(self).expect("should have parent")
948 }
949
950 pub fn is_implicit_bind(&self) -> bool {
958 self.expr().is_none()
959 }
960}
961
962impl<N: TreeNode> AstNode<N> for CallInputItem<N> {
963 fn can_cast(kind: SyntaxKind) -> bool {
964 kind == SyntaxKind::CallInputItemNode
965 }
966
967 fn cast(inner: N) -> Option<Self> {
968 match inner.kind() {
969 SyntaxKind::CallInputItemNode => Some(Self(inner)),
970 _ => None,
971 }
972 }
973
974 fn inner(&self) -> &N {
975 &self.0
976 }
977}
978
979#[derive(Clone, Debug, PartialEq, Eq)]
981pub struct WorkflowHintsSection<N: TreeNode = SyntaxNode>(N);
982
983impl<N: TreeNode> WorkflowHintsSection<N> {
984 pub fn items(&self) -> impl Iterator<Item = WorkflowHintsItem<N>> + use<'_, N> {
986 self.children()
987 }
988
989 pub fn parent(&self) -> WorkflowDefinition<N> {
991 <Self as AstNode<N>>::parent(self).expect("should have parent")
992 }
993}
994
995impl<N: TreeNode> AstNode<N> for WorkflowHintsSection<N> {
996 fn can_cast(kind: SyntaxKind) -> bool {
997 kind == SyntaxKind::WorkflowHintsSectionNode
998 }
999
1000 fn cast(inner: N) -> Option<Self> {
1001 match inner.kind() {
1002 SyntaxKind::WorkflowHintsSectionNode => Some(Self(inner)),
1003 _ => None,
1004 }
1005 }
1006
1007 fn inner(&self) -> &N {
1008 &self.0
1009 }
1010}
1011
1012#[derive(Clone, Debug, PartialEq, Eq)]
1014pub struct WorkflowHintsItem<N: TreeNode = SyntaxNode>(N);
1015
1016impl<N: TreeNode> WorkflowHintsItem<N> {
1017 pub fn name(&self) -> Ident<N::Token> {
1019 self.token().expect("expected an item name")
1020 }
1021
1022 pub fn value(&self) -> WorkflowHintsItemValue<N> {
1024 self.child().expect("expected an item value")
1025 }
1026}
1027
1028impl<N: TreeNode> AstNode<N> for WorkflowHintsItem<N> {
1029 fn can_cast(kind: SyntaxKind) -> bool {
1030 kind == SyntaxKind::WorkflowHintsItemNode
1031 }
1032
1033 fn cast(inner: N) -> Option<Self> {
1034 match inner.kind() {
1035 SyntaxKind::WorkflowHintsItemNode => Some(Self(inner)),
1036 _ => None,
1037 }
1038 }
1039
1040 fn inner(&self) -> &N {
1041 &self.0
1042 }
1043}
1044
1045#[derive(Clone, Debug, PartialEq, Eq)]
1047pub enum WorkflowHintsItemValue<N: TreeNode = SyntaxNode> {
1048 Boolean(LiteralBoolean<N>),
1050 Integer(LiteralInteger<N>),
1052 Float(LiteralFloat<N>),
1054 String(LiteralString<N>),
1056 Object(WorkflowHintsObject<N>),
1058 Array(WorkflowHintsArray<N>),
1060}
1061
1062impl<N: TreeNode> WorkflowHintsItemValue<N> {
1063 pub fn unwrap_boolean(self) -> LiteralBoolean<N> {
1069 match self {
1070 Self::Boolean(b) => b,
1071 _ => panic!("not a boolean"),
1072 }
1073 }
1074
1075 pub fn unwrap_integer(self) -> LiteralInteger<N> {
1081 match self {
1082 Self::Integer(i) => i,
1083 _ => panic!("not an integer"),
1084 }
1085 }
1086
1087 pub fn unwrap_float(self) -> LiteralFloat<N> {
1093 match self {
1094 Self::Float(f) => f,
1095 _ => panic!("not a float"),
1096 }
1097 }
1098
1099 pub fn unwrap_string(self) -> LiteralString<N> {
1105 match self {
1106 Self::String(s) => s,
1107 _ => panic!("not a string"),
1108 }
1109 }
1110
1111 pub fn unwrap_object(self) -> WorkflowHintsObject<N> {
1117 match self {
1118 Self::Object(o) => o,
1119 _ => panic!("not an object"),
1120 }
1121 }
1122
1123 pub fn unwrap_array(self) -> WorkflowHintsArray<N> {
1129 match self {
1130 Self::Array(a) => a,
1131 _ => panic!("not an array"),
1132 }
1133 }
1134}
1135
1136impl<N: TreeNode> AstNode<N> for WorkflowHintsItemValue<N> {
1137 fn can_cast(kind: SyntaxKind) -> bool {
1138 matches!(
1139 kind,
1140 SyntaxKind::LiteralBooleanNode
1141 | SyntaxKind::LiteralIntegerNode
1142 | SyntaxKind::LiteralFloatNode
1143 | SyntaxKind::LiteralStringNode
1144 | SyntaxKind::WorkflowHintsObjectNode
1145 | SyntaxKind::WorkflowHintsArrayNode
1146 )
1147 }
1148
1149 fn cast(inner: N) -> Option<Self> {
1150 match inner.kind() {
1151 SyntaxKind::LiteralBooleanNode => Some(Self::Boolean(LiteralBoolean(inner))),
1152 SyntaxKind::LiteralIntegerNode => Some(Self::Integer(LiteralInteger(inner))),
1153 SyntaxKind::LiteralFloatNode => Some(Self::Float(LiteralFloat(inner))),
1154 SyntaxKind::LiteralStringNode => Some(Self::String(LiteralString(inner))),
1155 SyntaxKind::WorkflowHintsObjectNode => Some(Self::Object(WorkflowHintsObject(inner))),
1156 SyntaxKind::WorkflowHintsArrayNode => Some(Self::Array(WorkflowHintsArray(inner))),
1157 _ => None,
1158 }
1159 }
1160
1161 fn inner(&self) -> &N {
1162 match self {
1163 Self::Boolean(b) => &b.0,
1164 Self::Integer(i) => &i.0,
1165 Self::Float(f) => &f.0,
1166 Self::String(s) => &s.0,
1167 Self::Object(o) => &o.0,
1168 Self::Array(a) => &a.0,
1169 }
1170 }
1171}
1172
1173#[derive(Clone, Debug, PartialEq, Eq)]
1175pub struct WorkflowHintsObject<N: TreeNode = SyntaxNode>(N);
1176
1177impl<N: TreeNode> WorkflowHintsObject<N> {
1178 pub fn items(&self) -> impl Iterator<Item = WorkflowHintsObjectItem<N>> + use<'_, N> {
1180 self.children()
1181 }
1182}
1183
1184impl<N: TreeNode> AstNode<N> for WorkflowHintsObject<N> {
1185 fn can_cast(kind: SyntaxKind) -> bool {
1186 kind == SyntaxKind::WorkflowHintsObjectNode
1187 }
1188
1189 fn cast(inner: N) -> Option<Self> {
1190 match inner.kind() {
1191 SyntaxKind::WorkflowHintsObjectNode => Some(Self(inner)),
1192 _ => None,
1193 }
1194 }
1195
1196 fn inner(&self) -> &N {
1197 &self.0
1198 }
1199}
1200
1201#[derive(Clone, Debug, PartialEq, Eq)]
1203pub struct WorkflowHintsObjectItem<N: TreeNode = SyntaxNode>(N);
1204
1205impl<N: TreeNode> WorkflowHintsObjectItem<N> {
1206 pub fn name(&self) -> Ident<N::Token> {
1208 self.token().expect("expected a name")
1209 }
1210
1211 pub fn value(&self) -> WorkflowHintsItemValue<N> {
1213 self.child().expect("expected a value")
1214 }
1215}
1216
1217impl<N: TreeNode> AstNode<N> for WorkflowHintsObjectItem<N> {
1218 fn can_cast(kind: SyntaxKind) -> bool {
1219 kind == SyntaxKind::WorkflowHintsObjectItemNode
1220 }
1221
1222 fn cast(inner: N) -> Option<Self> {
1223 match inner.kind() {
1224 SyntaxKind::WorkflowHintsObjectItemNode => Some(Self(inner)),
1225 _ => None,
1226 }
1227 }
1228
1229 fn inner(&self) -> &N {
1230 &self.0
1231 }
1232}
1233
1234#[derive(Clone, Debug, PartialEq, Eq)]
1236pub struct WorkflowHintsArray<N: TreeNode = SyntaxNode>(N);
1237
1238impl<N: TreeNode> WorkflowHintsArray<N> {
1239 pub fn elements(&self) -> impl Iterator<Item = WorkflowHintsItemValue<N>> + use<'_, N> {
1241 self.children()
1242 }
1243}
1244
1245impl<N: TreeNode> AstNode<N> for WorkflowHintsArray<N> {
1246 fn can_cast(kind: SyntaxKind) -> bool {
1247 kind == SyntaxKind::WorkflowHintsArrayNode
1248 }
1249
1250 fn cast(inner: N) -> Option<Self> {
1251 match inner.kind() {
1252 SyntaxKind::WorkflowHintsArrayNode => Some(Self(inner)),
1253 _ => None,
1254 }
1255 }
1256
1257 fn inner(&self) -> &N {
1258 &self.0
1259 }
1260}
1261
1262#[cfg(test)]
1263mod test {
1264 use super::*;
1265 use crate::Document;
1266
1267 #[test]
1268 fn workflows() {
1269 let (document, diagnostics) = Document::parse(
1270 r#"
1271version 1.1
1272
1273workflow test {
1274 input {
1275 String name
1276 Boolean do_thing
1277 }
1278
1279 output {
1280 String output = "hello, ~{name}!"
1281 }
1282
1283 if (do_thing) {
1284 call foo.my_task
1285
1286 scatter (a in [1, 2, 3]) {
1287 call my_task as my_task2 { input: a }
1288 }
1289 }
1290
1291 call my_task as my_task3 after my_task2 after my_task { input: a = 1 }
1292
1293 scatter (a in ["1", "2", "3"]) {
1294 # Do nothing
1295 }
1296
1297 meta {
1298 description: "a test"
1299 foo: null
1300 }
1301
1302 parameter_meta {
1303 name: {
1304 help: "a name to greet"
1305 }
1306 }
1307
1308 hints {
1309 foo: "bar"
1310 }
1311
1312 String x = "private"
1313}
1314"#,
1315 );
1316
1317 assert!(diagnostics.is_empty());
1318 let ast = document.ast();
1319 let ast = ast.as_v1().expect("should be a V1 AST");
1320 let workflows: Vec<_> = ast.workflows().collect();
1321 assert_eq!(workflows.len(), 1);
1322 assert_eq!(workflows[0].name().text(), "test");
1323
1324 let input = workflows[0]
1326 .input()
1327 .expect("workflow should have an input section");
1328 assert_eq!(input.parent().unwrap_workflow().name().text(), "test");
1329 let decls: Vec<_> = input.declarations().collect();
1330 assert_eq!(decls.len(), 2);
1331
1332 assert_eq!(
1334 decls[0].clone().unwrap_unbound_decl().ty().to_string(),
1335 "String"
1336 );
1337 assert_eq!(decls[0].clone().unwrap_unbound_decl().name().text(), "name");
1338
1339 assert_eq!(
1341 decls[1].clone().unwrap_unbound_decl().ty().to_string(),
1342 "Boolean"
1343 );
1344 assert_eq!(
1345 decls[1].clone().unwrap_unbound_decl().name().text(),
1346 "do_thing"
1347 );
1348
1349 let output = workflows[0]
1351 .output()
1352 .expect("workflow should have an output section");
1353 assert_eq!(output.parent().unwrap_workflow().name().text(), "test");
1354 let decls: Vec<_> = output.declarations().collect();
1355 assert_eq!(decls.len(), 1);
1356
1357 assert_eq!(decls[0].ty().to_string(), "String");
1359 assert_eq!(decls[0].name().text(), "output");
1360 let parts: Vec<_> = decls[0]
1361 .expr()
1362 .unwrap_literal()
1363 .unwrap_string()
1364 .parts()
1365 .collect();
1366 assert_eq!(parts.len(), 3);
1367 assert_eq!(parts[0].clone().unwrap_text().text(), "hello, ");
1368 assert_eq!(
1369 parts[1]
1370 .clone()
1371 .unwrap_placeholder()
1372 .expr()
1373 .unwrap_name_ref()
1374 .name()
1375 .text(),
1376 "name"
1377 );
1378 assert_eq!(parts[2].clone().unwrap_text().text(), "!");
1379
1380 let statements: Vec<_> = workflows[0].statements().collect();
1382 assert_eq!(statements.len(), 4);
1383
1384 let conditional = statements[0].clone().unwrap_conditional();
1386 assert_eq!(
1387 conditional.expr().unwrap_name_ref().name().text(),
1388 "do_thing"
1389 );
1390
1391 let inner: Vec<_> = conditional.statements().collect();
1393 assert_eq!(inner.len(), 2);
1394
1395 let call = inner[0].clone().unwrap_call();
1397 let names = call.target().names().collect::<Vec<_>>();
1398 assert_eq!(names.len(), 2);
1399 assert_eq!(names[0].text(), "foo");
1400 assert_eq!(names[1].text(), "my_task");
1401 assert!(call.alias().is_none());
1402 assert_eq!(call.after().count(), 0);
1403 assert_eq!(call.inputs().count(), 0);
1404
1405 let scatter = inner[1].clone().unwrap_scatter();
1407 assert_eq!(scatter.variable().text(), "a");
1408 let elements: Vec<_> = scatter
1409 .expr()
1410 .unwrap_literal()
1411 .unwrap_array()
1412 .elements()
1413 .collect();
1414 assert_eq!(elements.len(), 3);
1415 assert_eq!(
1416 elements[0]
1417 .clone()
1418 .unwrap_literal()
1419 .unwrap_integer()
1420 .value()
1421 .unwrap(),
1422 1
1423 );
1424 assert_eq!(
1425 elements[1]
1426 .clone()
1427 .unwrap_literal()
1428 .unwrap_integer()
1429 .value()
1430 .unwrap(),
1431 2
1432 );
1433 assert_eq!(
1434 elements[2]
1435 .clone()
1436 .unwrap_literal()
1437 .unwrap_integer()
1438 .value()
1439 .unwrap(),
1440 3
1441 );
1442
1443 let inner: Vec<_> = scatter.statements().collect();
1445 assert_eq!(inner.len(), 1);
1446
1447 let call = inner[0].clone().unwrap_call();
1449 let names = call.target().names().collect::<Vec<_>>();
1450 assert_eq!(names.len(), 1);
1451 assert_eq!(names[0].text(), "my_task");
1452 assert_eq!(call.alias().unwrap().name().text(), "my_task2");
1453 assert_eq!(call.after().count(), 0);
1454 let inputs: Vec<_> = call.inputs().collect();
1455 assert_eq!(inputs.len(), 1);
1456 assert_eq!(inputs[0].name().text(), "a");
1457 assert!(inputs[0].expr().is_none());
1458
1459 let call = statements[1].clone().unwrap_call();
1461 assert_eq!(names.len(), 1);
1462 assert_eq!(names[0].text(), "my_task");
1463 assert_eq!(call.alias().unwrap().name().text(), "my_task3");
1464 let after: Vec<_> = call.after().collect();
1465 assert_eq!(after.len(), 2);
1466 assert_eq!(after[0].name().text(), "my_task2");
1467 assert_eq!(after[1].name().text(), "my_task");
1468 let inputs: Vec<_> = call.inputs().collect();
1469 assert_eq!(inputs.len(), 1);
1470 assert_eq!(inputs[0].name().text(), "a");
1471 assert_eq!(
1472 inputs[0]
1473 .expr()
1474 .unwrap()
1475 .unwrap_literal()
1476 .unwrap_integer()
1477 .value()
1478 .unwrap(),
1479 1
1480 );
1481
1482 let scatter = statements[2].clone().unwrap_scatter();
1484 assert_eq!(scatter.variable().text(), "a");
1485 let elements: Vec<_> = scatter
1486 .expr()
1487 .unwrap_literal()
1488 .unwrap_array()
1489 .elements()
1490 .collect();
1491 assert_eq!(elements.len(), 3);
1492 assert_eq!(
1493 elements[0]
1494 .clone()
1495 .unwrap_literal()
1496 .unwrap_string()
1497 .text()
1498 .unwrap()
1499 .text(),
1500 "1"
1501 );
1502 assert_eq!(
1503 elements[1]
1504 .clone()
1505 .unwrap_literal()
1506 .unwrap_string()
1507 .text()
1508 .unwrap()
1509 .text(),
1510 "2"
1511 );
1512 assert_eq!(
1513 elements[2]
1514 .clone()
1515 .unwrap_literal()
1516 .unwrap_string()
1517 .text()
1518 .unwrap()
1519 .text(),
1520 "3"
1521 );
1522
1523 let inner: Vec<_> = scatter.statements().collect();
1525 assert_eq!(inner.len(), 0);
1526
1527 let metadata = workflows[0]
1529 .metadata()
1530 .expect("workflow should have a metadata section");
1531 assert_eq!(metadata.parent().unwrap_workflow().name().text(), "test");
1532 let items: Vec<_> = metadata.items().collect();
1533 assert_eq!(items.len(), 2);
1534 assert_eq!(items[0].name().text(), "description");
1535 assert_eq!(
1536 items[0].value().unwrap_string().text().unwrap().text(),
1537 "a test"
1538 );
1539 assert_eq!(items[1].name().text(), "foo");
1540 items[1].value().unwrap_null();
1541
1542 let param_meta = workflows[0]
1544 .parameter_metadata()
1545 .expect("workflow should have a parameter metadata section");
1546 assert_eq!(param_meta.parent().unwrap_workflow().name().text(), "test");
1547 let items: Vec<_> = param_meta.items().collect();
1548 assert_eq!(items.len(), 1);
1549 assert_eq!(items[0].name().text(), "name");
1550 let items: Vec<_> = items[0].value().unwrap_object().items().collect();
1551 assert_eq!(items.len(), 1);
1552 assert_eq!(items[0].name().text(), "help");
1553 assert_eq!(
1554 items[0].value().unwrap_string().text().unwrap().text(),
1555 "a name to greet"
1556 );
1557
1558 let hints = workflows[0]
1560 .hints()
1561 .expect("workflow should have a hints section");
1562 assert_eq!(hints.parent().name().text(), "test");
1563 let items: Vec<_> = hints.items().collect();
1564 assert_eq!(items.len(), 1);
1565 assert_eq!(items[0].name().text(), "foo");
1566 assert_eq!(
1567 items[0].value().unwrap_string().text().unwrap().text(),
1568 "bar"
1569 );
1570
1571 let decls: Vec<_> = workflows[0].declarations().collect();
1573 assert_eq!(decls.len(), 1);
1574
1575 assert_eq!(decls[0].ty().to_string(), "String");
1577 assert_eq!(decls[0].name().text(), "x");
1578 assert_eq!(
1579 decls[0]
1580 .expr()
1581 .unwrap_literal()
1582 .unwrap_string()
1583 .text()
1584 .unwrap()
1585 .text(),
1586 "private"
1587 );
1588 }
1589}