1use wdl_grammar::SupportedVersion;
4use wdl_grammar::version::V1;
5
6use super::BoundDecl;
7use super::Expr;
8use super::InputSection;
9use super::LiteralBoolean;
10use super::LiteralFloat;
11use super::LiteralInteger;
12use super::LiteralString;
13use super::MetadataSection;
14use super::MetadataValue;
15use super::OutputSection;
16use super::ParameterMetadataSection;
17use crate::AstChildren;
18use crate::AstNode;
19use crate::AstToken;
20use crate::Ident;
21use crate::SyntaxElement;
22use crate::SyntaxKind;
23use crate::SyntaxNode;
24use crate::WorkflowDescriptionLanguage;
25use crate::support::child;
26use crate::support::children;
27use crate::token;
28
29pub const WORKFLOW_HINT_ALLOW_NESTED_INPUTS: &str = "allow_nested_inputs";
31
32pub const WORKFLOW_HINT_ALLOW_NESTED_INPUTS_ALIAS: &str = "allowNestedInputs";
35
36#[derive(Clone, Debug, PartialEq, Eq)]
38pub struct WorkflowDefinition(pub(crate) SyntaxNode);
39
40impl WorkflowDefinition {
41 pub fn name(&self) -> Ident {
43 token(&self.0).expect("workflow should have a name")
44 }
45
46 pub fn items(&self) -> impl Iterator<Item = WorkflowItem> + use<> {
48 WorkflowItem::children(&self.0)
49 }
50
51 pub fn input(&self) -> Option<InputSection> {
53 child(&self.0)
54 }
55
56 pub fn output(&self) -> Option<OutputSection> {
58 child(&self.0)
59 }
60
61 pub fn statements(&self) -> impl Iterator<Item = WorkflowStatement> + use<> {
63 WorkflowStatement::children(&self.0)
64 }
65
66 pub fn metadata(&self) -> Option<MetadataSection> {
68 child(&self.0)
69 }
70
71 pub fn parameter_metadata(&self) -> Option<ParameterMetadataSection> {
73 child(&self.0)
74 }
75
76 pub fn hints(&self) -> Option<WorkflowHintsSection> {
78 child(&self.0)
79 }
80
81 pub fn declarations(&self) -> AstChildren<BoundDecl> {
83 children(&self.0)
84 }
85
86 pub fn allows_nested_inputs(&self, version: SupportedVersion) -> bool {
88 match version {
89 SupportedVersion::V1(V1::Zero) => return true,
90 SupportedVersion::V1(V1::One) => {
91 }
93 SupportedVersion::V1(V1::Two) => {
94 let allow = self.hints().and_then(|s| {
96 s.items().find_map(|i| {
97 let name = i.name();
98 if name.as_str() == WORKFLOW_HINT_ALLOW_NESTED_INPUTS
99 || name.as_str() == WORKFLOW_HINT_ALLOW_NESTED_INPUTS_ALIAS
100 {
101 match i.value() {
102 WorkflowHintsItemValue::Boolean(v) => Some(v.value()),
103 _ => Some(false),
104 }
105 } else {
106 None
107 }
108 })
109 });
110
111 if let Some(allow) = allow {
112 return allow;
113 }
114
115 }
117 _ => return false,
118 }
119
120 self.metadata()
122 .and_then(|s| {
123 s.items().find_map(|i| {
124 if i.name().as_str() == "allowNestedInputs" {
125 match i.value() {
126 MetadataValue::Boolean(v) => Some(v.value()),
127 _ => Some(false),
128 }
129 } else {
130 None
131 }
132 })
133 })
134 .unwrap_or(false)
135 }
136}
137
138impl AstNode for WorkflowDefinition {
139 type Language = WorkflowDescriptionLanguage;
140
141 fn can_cast(kind: SyntaxKind) -> bool
142 where
143 Self: Sized,
144 {
145 kind == SyntaxKind::WorkflowDefinitionNode
146 }
147
148 fn cast(syntax: SyntaxNode) -> Option<Self>
149 where
150 Self: Sized,
151 {
152 match syntax.kind() {
153 SyntaxKind::WorkflowDefinitionNode => Some(Self(syntax)),
154 _ => None,
155 }
156 }
157
158 fn syntax(&self) -> &SyntaxNode {
159 &self.0
160 }
161}
162
163#[derive(Clone, Debug, PartialEq, Eq)]
165pub enum WorkflowItem {
166 Input(InputSection),
168 Output(OutputSection),
170 Conditional(ConditionalStatement),
172 Scatter(ScatterStatement),
174 Call(CallStatement),
176 Metadata(MetadataSection),
178 ParameterMetadata(ParameterMetadataSection),
180 Hints(WorkflowHintsSection),
182 Declaration(BoundDecl),
184}
185
186impl WorkflowItem {
187 pub fn can_cast(kind: SyntaxKind) -> bool
190 where
191 Self: Sized,
192 {
193 matches!(
194 kind,
195 SyntaxKind::InputSectionNode
196 | SyntaxKind::OutputSectionNode
197 | SyntaxKind::ConditionalStatementNode
198 | SyntaxKind::ScatterStatementNode
199 | SyntaxKind::CallStatementNode
200 | SyntaxKind::MetadataSectionNode
201 | SyntaxKind::ParameterMetadataSectionNode
202 | SyntaxKind::WorkflowHintsSectionNode
203 | SyntaxKind::BoundDeclNode
204 )
205 }
206
207 pub fn cast(syntax: SyntaxNode) -> Option<Self>
210 where
211 Self: Sized,
212 {
213 match syntax.kind() {
214 SyntaxKind::InputSectionNode => Some(Self::Input(
215 InputSection::cast(syntax).expect("input section to cast"),
216 )),
217 SyntaxKind::OutputSectionNode => Some(Self::Output(
218 OutputSection::cast(syntax).expect("output section to cast"),
219 )),
220 SyntaxKind::ConditionalStatementNode => Some(Self::Conditional(
221 ConditionalStatement::cast(syntax).expect("conditional statement to cast"),
222 )),
223 SyntaxKind::ScatterStatementNode => Some(Self::Scatter(
224 ScatterStatement::cast(syntax).expect("scatter statement to cast"),
225 )),
226 SyntaxKind::CallStatementNode => Some(Self::Call(
227 CallStatement::cast(syntax).expect("call statement to cast"),
228 )),
229 SyntaxKind::MetadataSectionNode => Some(Self::Metadata(
230 MetadataSection::cast(syntax).expect("metadata section to cast"),
231 )),
232 SyntaxKind::ParameterMetadataSectionNode => Some(Self::ParameterMetadata(
233 ParameterMetadataSection::cast(syntax).expect("parameter metadata section to cast"),
234 )),
235 SyntaxKind::WorkflowHintsSectionNode => Some(Self::Hints(
236 WorkflowHintsSection::cast(syntax).expect("workflow hints section to cast"),
237 )),
238 SyntaxKind::BoundDeclNode => Some(Self::Declaration(
239 BoundDecl::cast(syntax).expect("bound decl to cast"),
240 )),
241 _ => None,
242 }
243 }
244
245 pub fn syntax(&self) -> &SyntaxNode {
247 match self {
248 Self::Input(element) => element.syntax(),
249 Self::Output(element) => element.syntax(),
250 Self::Conditional(element) => element.syntax(),
251 Self::Scatter(element) => element.syntax(),
252 Self::Call(element) => element.syntax(),
253 Self::Metadata(element) => element.syntax(),
254 Self::ParameterMetadata(element) => element.syntax(),
255 Self::Hints(element) => element.syntax(),
256 Self::Declaration(element) => element.syntax(),
257 }
258 }
259
260 pub fn as_input_section(&self) -> Option<&InputSection> {
266 match self {
267 Self::Input(input_section) => Some(input_section),
268 _ => None,
269 }
270 }
271
272 pub fn into_input_section(self) -> Option<InputSection> {
278 match self {
279 Self::Input(input_section) => Some(input_section),
280 _ => None,
281 }
282 }
283
284 pub fn as_output_section(&self) -> Option<&OutputSection> {
290 match self {
291 Self::Output(output_section) => Some(output_section),
292 _ => None,
293 }
294 }
295
296 pub fn into_output_section(self) -> Option<OutputSection> {
302 match self {
303 Self::Output(output_section) => Some(output_section),
304 _ => None,
305 }
306 }
307
308 pub fn as_conditional(&self) -> Option<&ConditionalStatement> {
314 match self {
315 Self::Conditional(conditional) => Some(conditional),
316 _ => None,
317 }
318 }
319
320 pub fn into_conditional(self) -> Option<ConditionalStatement> {
327 match self {
328 Self::Conditional(conditional) => Some(conditional),
329 _ => None,
330 }
331 }
332
333 pub fn as_scatter(&self) -> Option<&ScatterStatement> {
339 match self {
340 Self::Scatter(scatter) => Some(scatter),
341 _ => None,
342 }
343 }
344
345 pub fn into_scatter(self) -> Option<ScatterStatement> {
352 match self {
353 Self::Scatter(scatter) => Some(scatter),
354 _ => None,
355 }
356 }
357
358 pub fn as_call(&self) -> Option<&CallStatement> {
364 match self {
365 Self::Call(call) => Some(call),
366 _ => None,
367 }
368 }
369
370 pub fn into_call(self) -> Option<CallStatement> {
376 match self {
377 Self::Call(call) => Some(call),
378 _ => None,
379 }
380 }
381
382 pub fn as_metadata_section(&self) -> Option<&MetadataSection> {
388 match self {
389 Self::Metadata(metadata_section) => Some(metadata_section),
390 _ => None,
391 }
392 }
393
394 pub fn into_metadata_section(self) -> Option<MetadataSection> {
400 match self {
401 Self::Metadata(metadata_section) => Some(metadata_section),
402 _ => None,
403 }
404 }
405
406 pub fn as_parameter_metadata_section(&self) -> Option<&ParameterMetadataSection> {
413 match self {
414 Self::ParameterMetadata(parameter_metadata_section) => Some(parameter_metadata_section),
415 _ => None,
416 }
417 }
418
419 pub fn into_parameter_metadata_section(self) -> Option<ParameterMetadataSection> {
426 match self {
427 Self::ParameterMetadata(parameter_metadata_section) => Some(parameter_metadata_section),
428 _ => None,
429 }
430 }
431
432 pub fn as_hints_section(&self) -> Option<&WorkflowHintsSection> {
438 match self {
439 Self::Hints(hints_section) => Some(hints_section),
440 _ => None,
441 }
442 }
443
444 pub fn into_hints_section(self) -> Option<WorkflowHintsSection> {
451 match self {
452 Self::Hints(hints_section) => Some(hints_section),
453 _ => None,
454 }
455 }
456
457 pub fn as_declaration(&self) -> Option<&BoundDecl> {
463 match self {
464 Self::Declaration(declaration) => Some(declaration),
465 _ => None,
466 }
467 }
468
469 pub fn into_declaration(self) -> Option<BoundDecl> {
475 match self {
476 Self::Declaration(declaration) => Some(declaration),
477 _ => None,
478 }
479 }
480
481 pub fn child(syntax: &SyntaxNode) -> Option<Self> {
487 syntax.children().find_map(Self::cast)
488 }
489
490 pub fn children(syntax: &SyntaxNode) -> impl Iterator<Item = WorkflowItem> + use<> {
496 syntax.children().filter_map(Self::cast)
497 }
498}
499
500#[derive(Clone, Debug, PartialEq, Eq)]
502pub enum WorkflowStatement {
503 Conditional(ConditionalStatement),
505 Scatter(ScatterStatement),
507 Call(CallStatement),
509 Declaration(BoundDecl),
511}
512
513impl WorkflowStatement {
514 pub fn can_cast(kind: SyntaxKind) -> bool
517 where
518 Self: Sized,
519 {
520 matches!(
521 kind,
522 SyntaxKind::ConditionalStatementNode
523 | SyntaxKind::ScatterStatementNode
524 | SyntaxKind::CallStatementNode
525 | SyntaxKind::BoundDeclNode
526 )
527 }
528
529 pub fn cast(syntax: SyntaxNode) -> Option<Self>
532 where
533 Self: Sized,
534 {
535 match syntax.kind() {
536 SyntaxKind::ConditionalStatementNode => Some(Self::Conditional(
537 ConditionalStatement::cast(syntax).expect("conditional statement to cast"),
538 )),
539 SyntaxKind::ScatterStatementNode => Some(Self::Scatter(
540 ScatterStatement::cast(syntax).expect("scatter statement to cast"),
541 )),
542 SyntaxKind::CallStatementNode => Some(Self::Call(
543 CallStatement::cast(syntax).expect("call statement to cast"),
544 )),
545 SyntaxKind::BoundDeclNode => Some(Self::Declaration(
546 BoundDecl::cast(syntax).expect("bound decl to cast"),
547 )),
548 _ => None,
549 }
550 }
551
552 pub fn syntax(&self) -> &SyntaxNode {
554 match self {
555 Self::Conditional(element) => element.syntax(),
556 Self::Scatter(element) => element.syntax(),
557 Self::Call(element) => element.syntax(),
558 Self::Declaration(element) => element.syntax(),
559 }
560 }
561
562 pub fn as_conditional(&self) -> Option<&ConditionalStatement> {
568 match self {
569 Self::Conditional(conditional) => Some(conditional),
570 _ => None,
571 }
572 }
573
574 pub fn into_conditional(self) -> Option<ConditionalStatement> {
581 match self {
582 Self::Conditional(conditional) => Some(conditional),
583 _ => None,
584 }
585 }
586
587 pub fn unwrap_conditional(self) -> ConditionalStatement {
593 match self {
594 Self::Conditional(stmt) => stmt,
595 _ => panic!("not a conditional statement"),
596 }
597 }
598
599 pub fn as_scatter(&self) -> Option<&ScatterStatement> {
605 match self {
606 Self::Scatter(scatter) => Some(scatter),
607 _ => None,
608 }
609 }
610
611 pub fn into_scatter(self) -> Option<ScatterStatement> {
618 match self {
619 Self::Scatter(scatter) => Some(scatter),
620 _ => None,
621 }
622 }
623
624 pub fn unwrap_scatter(self) -> ScatterStatement {
630 match self {
631 Self::Scatter(stmt) => stmt,
632 _ => panic!("not a scatter statement"),
633 }
634 }
635
636 pub fn as_call(&self) -> Option<&CallStatement> {
642 match self {
643 Self::Call(call) => Some(call),
644 _ => None,
645 }
646 }
647
648 pub fn into_call(self) -> Option<CallStatement> {
655 match self {
656 Self::Call(call) => Some(call),
657 _ => None,
658 }
659 }
660
661 pub fn unwrap_call(self) -> CallStatement {
667 match self {
668 Self::Call(stmt) => stmt,
669 _ => panic!("not a call statement"),
670 }
671 }
672
673 pub fn as_declaration(&self) -> Option<&BoundDecl> {
679 match self {
680 Self::Declaration(declaration) => Some(declaration),
681 _ => None,
682 }
683 }
684
685 pub fn into_declaration(self) -> Option<BoundDecl> {
692 match self {
693 Self::Declaration(declaration) => Some(declaration),
694 _ => None,
695 }
696 }
697
698 pub fn unwrap_declaration(self) -> BoundDecl {
704 match self {
705 Self::Declaration(declaration) => declaration,
706 _ => panic!("not a bound declaration"),
707 }
708 }
709
710 pub fn child(syntax: &SyntaxNode) -> Option<Self> {
716 syntax.children().find_map(Self::cast)
717 }
718
719 pub fn children(syntax: &SyntaxNode) -> impl Iterator<Item = WorkflowStatement> + use<> {
725 syntax.children().filter_map(Self::cast)
726 }
727}
728
729#[derive(Clone, Debug, PartialEq, Eq)]
731pub struct ConditionalStatement(pub(crate) SyntaxNode);
732
733impl ConditionalStatement {
734 pub fn expr(&self) -> Expr {
736 Expr::child(&self.0).expect("expected a conditional expression")
737 }
738
739 pub fn statements(&self) -> impl Iterator<Item = WorkflowStatement> + use<> {
741 WorkflowStatement::children(&self.0)
742 }
743}
744
745impl AstNode for ConditionalStatement {
746 type Language = WorkflowDescriptionLanguage;
747
748 fn can_cast(kind: SyntaxKind) -> bool
749 where
750 Self: Sized,
751 {
752 kind == SyntaxKind::ConditionalStatementNode
753 }
754
755 fn cast(syntax: SyntaxNode) -> Option<Self>
756 where
757 Self: Sized,
758 {
759 match syntax.kind() {
760 SyntaxKind::ConditionalStatementNode => Some(Self(syntax)),
761 _ => None,
762 }
763 }
764
765 fn syntax(&self) -> &SyntaxNode {
766 &self.0
767 }
768}
769
770#[derive(Clone, Debug, PartialEq, Eq)]
772pub struct ScatterStatement(pub(crate) SyntaxNode);
773
774impl ScatterStatement {
775 pub fn variable(&self) -> Ident {
777 token(&self.0).expect("expected a scatter variable identifier")
778 }
779
780 pub fn expr(&self) -> Expr {
782 Expr::child(&self.0).expect("expected a scatter expression")
783 }
784
785 pub fn statements(&self) -> impl Iterator<Item = WorkflowStatement> + use<> {
787 WorkflowStatement::children(&self.0)
788 }
789}
790
791impl AstNode for ScatterStatement {
792 type Language = WorkflowDescriptionLanguage;
793
794 fn can_cast(kind: SyntaxKind) -> bool
795 where
796 Self: Sized,
797 {
798 kind == SyntaxKind::ScatterStatementNode
799 }
800
801 fn cast(syntax: SyntaxNode) -> Option<Self>
802 where
803 Self: Sized,
804 {
805 match syntax.kind() {
806 SyntaxKind::ScatterStatementNode => Some(Self(syntax)),
807 _ => None,
808 }
809 }
810
811 fn syntax(&self) -> &SyntaxNode {
812 &self.0
813 }
814}
815
816#[derive(Clone, Debug, PartialEq, Eq)]
818pub struct CallStatement(pub(crate) SyntaxNode);
819
820impl CallStatement {
821 pub fn target(&self) -> CallTarget {
823 child(&self.0).expect("expected a call target")
824 }
825
826 pub fn alias(&self) -> Option<CallAlias> {
828 child(&self.0)
829 }
830
831 pub fn after(&self) -> AstChildren<CallAfter> {
833 children(&self.0)
834 }
835
836 pub fn inputs(&self) -> AstChildren<CallInputItem> {
838 children(&self.0)
839 }
840}
841
842impl AstNode for CallStatement {
843 type Language = WorkflowDescriptionLanguage;
844
845 fn can_cast(kind: SyntaxKind) -> bool
846 where
847 Self: Sized,
848 {
849 kind == SyntaxKind::CallStatementNode
850 }
851
852 fn cast(syntax: SyntaxNode) -> Option<Self>
853 where
854 Self: Sized,
855 {
856 match syntax.kind() {
857 SyntaxKind::CallStatementNode => Some(Self(syntax)),
858 _ => None,
859 }
860 }
861
862 fn syntax(&self) -> &SyntaxNode {
863 &self.0
864 }
865}
866
867#[derive(Clone, Debug, PartialEq, Eq)]
869pub struct CallTarget(SyntaxNode);
870
871impl CallTarget {
872 pub fn names(&self) -> impl Iterator<Item = Ident> + use<> {
877 self.0
878 .children_with_tokens()
879 .filter_map(SyntaxElement::into_token)
880 .filter_map(Ident::cast)
881 }
882}
883
884impl AstNode for CallTarget {
885 type Language = WorkflowDescriptionLanguage;
886
887 fn can_cast(kind: SyntaxKind) -> bool
888 where
889 Self: Sized,
890 {
891 kind == SyntaxKind::CallTargetNode
892 }
893
894 fn cast(syntax: SyntaxNode) -> Option<Self>
895 where
896 Self: Sized,
897 {
898 match syntax.kind() {
899 SyntaxKind::CallTargetNode => Some(Self(syntax)),
900 _ => None,
901 }
902 }
903
904 fn syntax(&self) -> &SyntaxNode {
905 &self.0
906 }
907}
908
909#[derive(Clone, Debug, PartialEq, Eq)]
911pub struct CallAlias(SyntaxNode);
912
913impl CallAlias {
914 pub fn name(&self) -> Ident {
916 token(&self.0).expect("expected a alias identifier")
917 }
918}
919
920impl AstNode for CallAlias {
921 type Language = WorkflowDescriptionLanguage;
922
923 fn can_cast(kind: SyntaxKind) -> bool
924 where
925 Self: Sized,
926 {
927 kind == SyntaxKind::CallAliasNode
928 }
929
930 fn cast(syntax: SyntaxNode) -> Option<Self>
931 where
932 Self: Sized,
933 {
934 match syntax.kind() {
935 SyntaxKind::CallAliasNode => Some(Self(syntax)),
936 _ => None,
937 }
938 }
939
940 fn syntax(&self) -> &SyntaxNode {
941 &self.0
942 }
943}
944
945#[derive(Clone, Debug, PartialEq, Eq)]
947pub struct CallAfter(SyntaxNode);
948
949impl CallAfter {
950 pub fn name(&self) -> Ident {
952 token(&self.0).expect("expected an after identifier")
953 }
954}
955
956impl AstNode for CallAfter {
957 type Language = WorkflowDescriptionLanguage;
958
959 fn can_cast(kind: SyntaxKind) -> bool
960 where
961 Self: Sized,
962 {
963 kind == SyntaxKind::CallAfterNode
964 }
965
966 fn cast(syntax: SyntaxNode) -> Option<Self>
967 where
968 Self: Sized,
969 {
970 match syntax.kind() {
971 SyntaxKind::CallAfterNode => Some(Self(syntax)),
972 _ => None,
973 }
974 }
975
976 fn syntax(&self) -> &SyntaxNode {
977 &self.0
978 }
979}
980
981#[derive(Clone, Debug, PartialEq, Eq)]
983pub struct CallInputItem(SyntaxNode);
984
985impl CallInputItem {
986 pub fn name(&self) -> Ident {
988 token(&self.0).expect("expected an input name")
989 }
990
991 pub fn expr(&self) -> Option<Expr> {
993 Expr::child(&self.0)
994 }
995
996 pub fn parent(&self) -> CallStatement {
998 CallStatement::cast(self.0.parent().expect("should have parent")).expect("node should cast")
999 }
1000}
1001
1002impl AstNode for CallInputItem {
1003 type Language = WorkflowDescriptionLanguage;
1004
1005 fn can_cast(kind: SyntaxKind) -> bool
1006 where
1007 Self: Sized,
1008 {
1009 kind == SyntaxKind::CallInputItemNode
1010 }
1011
1012 fn cast(syntax: SyntaxNode) -> Option<Self>
1013 where
1014 Self: Sized,
1015 {
1016 match syntax.kind() {
1017 SyntaxKind::CallInputItemNode => Some(Self(syntax)),
1018 _ => None,
1019 }
1020 }
1021
1022 fn syntax(&self) -> &SyntaxNode {
1023 &self.0
1024 }
1025}
1026
1027#[derive(Clone, Debug, PartialEq, Eq)]
1029pub struct WorkflowHintsSection(pub(crate) SyntaxNode);
1030
1031impl WorkflowHintsSection {
1032 pub fn items(&self) -> AstChildren<WorkflowHintsItem> {
1034 children(&self.0)
1035 }
1036
1037 pub fn parent(&self) -> WorkflowDefinition {
1039 WorkflowDefinition::cast(self.0.parent().expect("should have a parent"))
1040 .expect("parent should cast")
1041 }
1042}
1043
1044impl AstNode for WorkflowHintsSection {
1045 type Language = WorkflowDescriptionLanguage;
1046
1047 fn can_cast(kind: SyntaxKind) -> bool
1048 where
1049 Self: Sized,
1050 {
1051 kind == SyntaxKind::WorkflowHintsSectionNode
1052 }
1053
1054 fn cast(syntax: SyntaxNode) -> Option<Self>
1055 where
1056 Self: Sized,
1057 {
1058 match syntax.kind() {
1059 SyntaxKind::WorkflowHintsSectionNode => Some(Self(syntax)),
1060 _ => None,
1061 }
1062 }
1063
1064 fn syntax(&self) -> &SyntaxNode {
1065 &self.0
1066 }
1067}
1068
1069#[derive(Clone, Debug, PartialEq, Eq)]
1071pub struct WorkflowHintsItem(SyntaxNode);
1072
1073impl WorkflowHintsItem {
1074 pub fn name(&self) -> Ident {
1076 token(&self.0).expect("expected an item name")
1077 }
1078
1079 pub fn value(&self) -> WorkflowHintsItemValue {
1081 child(&self.0).expect("expected an item value")
1082 }
1083}
1084
1085impl AstNode for WorkflowHintsItem {
1086 type Language = WorkflowDescriptionLanguage;
1087
1088 fn can_cast(kind: SyntaxKind) -> bool
1089 where
1090 Self: Sized,
1091 {
1092 kind == SyntaxKind::WorkflowHintsItemNode
1093 }
1094
1095 fn cast(syntax: SyntaxNode) -> Option<Self>
1096 where
1097 Self: Sized,
1098 {
1099 match syntax.kind() {
1100 SyntaxKind::WorkflowHintsItemNode => Some(Self(syntax)),
1101 _ => None,
1102 }
1103 }
1104
1105 fn syntax(&self) -> &SyntaxNode {
1106 &self.0
1107 }
1108}
1109
1110#[derive(Clone, Debug, PartialEq, Eq)]
1112pub enum WorkflowHintsItemValue {
1113 Boolean(LiteralBoolean),
1115 Integer(LiteralInteger),
1117 Float(LiteralFloat),
1119 String(LiteralString),
1121 Object(WorkflowHintsObject),
1123 Array(WorkflowHintsArray),
1125}
1126
1127impl WorkflowHintsItemValue {
1128 pub fn unwrap_boolean(self) -> LiteralBoolean {
1134 match self {
1135 Self::Boolean(b) => b,
1136 _ => panic!("not a boolean"),
1137 }
1138 }
1139
1140 pub fn unwrap_integer(self) -> LiteralInteger {
1146 match self {
1147 Self::Integer(i) => i,
1148 _ => panic!("not an integer"),
1149 }
1150 }
1151
1152 pub fn unwrap_float(self) -> LiteralFloat {
1158 match self {
1159 Self::Float(f) => f,
1160 _ => panic!("not a float"),
1161 }
1162 }
1163
1164 pub fn unwrap_string(self) -> LiteralString {
1170 match self {
1171 Self::String(s) => s,
1172 _ => panic!("not a string"),
1173 }
1174 }
1175
1176 pub fn unwrap_object(self) -> WorkflowHintsObject {
1182 match self {
1183 Self::Object(o) => o,
1184 _ => panic!("not an object"),
1185 }
1186 }
1187
1188 pub fn unwrap_array(self) -> WorkflowHintsArray {
1194 match self {
1195 Self::Array(a) => a,
1196 _ => panic!("not an array"),
1197 }
1198 }
1199}
1200
1201impl AstNode for WorkflowHintsItemValue {
1202 type Language = WorkflowDescriptionLanguage;
1203
1204 fn can_cast(kind: SyntaxKind) -> bool
1205 where
1206 Self: Sized,
1207 {
1208 matches!(
1209 kind,
1210 SyntaxKind::LiteralBooleanNode
1211 | SyntaxKind::LiteralIntegerNode
1212 | SyntaxKind::LiteralFloatNode
1213 | SyntaxKind::LiteralStringNode
1214 | SyntaxKind::WorkflowHintsObjectNode
1215 | SyntaxKind::WorkflowHintsArrayNode
1216 )
1217 }
1218
1219 fn cast(syntax: SyntaxNode) -> Option<Self>
1220 where
1221 Self: Sized,
1222 {
1223 match syntax.kind() {
1224 SyntaxKind::LiteralBooleanNode => Some(Self::Boolean(LiteralBoolean(syntax))),
1225 SyntaxKind::LiteralIntegerNode => Some(Self::Integer(LiteralInteger(syntax))),
1226 SyntaxKind::LiteralFloatNode => Some(Self::Float(LiteralFloat(syntax))),
1227 SyntaxKind::LiteralStringNode => Some(Self::String(LiteralString(syntax))),
1228 SyntaxKind::WorkflowHintsObjectNode => Some(Self::Object(WorkflowHintsObject(syntax))),
1229 SyntaxKind::WorkflowHintsArrayNode => Some(Self::Array(WorkflowHintsArray(syntax))),
1230 _ => None,
1231 }
1232 }
1233
1234 fn syntax(&self) -> &SyntaxNode {
1235 match self {
1236 Self::Boolean(b) => &b.0,
1237 Self::Integer(i) => &i.0,
1238 Self::Float(f) => &f.0,
1239 Self::String(s) => &s.0,
1240 Self::Object(o) => &o.0,
1241 Self::Array(a) => &a.0,
1242 }
1243 }
1244}
1245
1246#[derive(Clone, Debug, PartialEq, Eq)]
1248pub struct WorkflowHintsObject(pub(crate) SyntaxNode);
1249
1250impl WorkflowHintsObject {
1251 pub fn items(&self) -> AstChildren<WorkflowHintsObjectItem> {
1253 children(&self.0)
1254 }
1255}
1256
1257impl AstNode for WorkflowHintsObject {
1258 type Language = WorkflowDescriptionLanguage;
1259
1260 fn can_cast(kind: SyntaxKind) -> bool
1261 where
1262 Self: Sized,
1263 {
1264 kind == SyntaxKind::WorkflowHintsObjectNode
1265 }
1266
1267 fn cast(syntax: SyntaxNode) -> Option<Self>
1268 where
1269 Self: Sized,
1270 {
1271 match syntax.kind() {
1272 SyntaxKind::WorkflowHintsObjectNode => Some(Self(syntax)),
1273 _ => None,
1274 }
1275 }
1276
1277 fn syntax(&self) -> &SyntaxNode {
1278 &self.0
1279 }
1280}
1281
1282#[derive(Clone, Debug, PartialEq, Eq)]
1284pub struct WorkflowHintsObjectItem(pub(crate) SyntaxNode);
1285
1286impl WorkflowHintsObjectItem {
1287 pub fn name(&self) -> Ident {
1289 token(&self.0).expect("expected a name")
1290 }
1291
1292 pub fn value(&self) -> WorkflowHintsItemValue {
1294 child(&self.0).expect("expected a value")
1295 }
1296}
1297
1298impl AstNode for WorkflowHintsObjectItem {
1299 type Language = WorkflowDescriptionLanguage;
1300
1301 fn can_cast(kind: SyntaxKind) -> bool
1302 where
1303 Self: Sized,
1304 {
1305 kind == SyntaxKind::WorkflowHintsObjectItemNode
1306 }
1307
1308 fn cast(syntax: SyntaxNode) -> Option<Self>
1309 where
1310 Self: Sized,
1311 {
1312 match syntax.kind() {
1313 SyntaxKind::WorkflowHintsObjectItemNode => Some(Self(syntax)),
1314 _ => None,
1315 }
1316 }
1317
1318 fn syntax(&self) -> &SyntaxNode {
1319 &self.0
1320 }
1321}
1322
1323#[derive(Clone, Debug, PartialEq, Eq)]
1325pub struct WorkflowHintsArray(pub(crate) SyntaxNode);
1326
1327impl WorkflowHintsArray {
1328 pub fn elements(&self) -> AstChildren<WorkflowHintsItemValue> {
1330 children(&self.0)
1331 }
1332}
1333
1334impl AstNode for WorkflowHintsArray {
1335 type Language = WorkflowDescriptionLanguage;
1336
1337 fn can_cast(kind: SyntaxKind) -> bool
1338 where
1339 Self: Sized,
1340 {
1341 kind == SyntaxKind::WorkflowHintsArrayNode
1342 }
1343
1344 fn cast(syntax: SyntaxNode) -> Option<Self>
1345 where
1346 Self: Sized,
1347 {
1348 match syntax.kind() {
1349 SyntaxKind::WorkflowHintsArrayNode => Some(Self(syntax)),
1350 _ => None,
1351 }
1352 }
1353
1354 fn syntax(&self) -> &SyntaxNode {
1355 &self.0
1356 }
1357}
1358
1359#[cfg(test)]
1360mod test {
1361 use super::*;
1362 use crate::Document;
1363 use crate::SupportedVersion;
1364 use crate::VisitReason;
1365 use crate::Visitor;
1366 use crate::v1::UnboundDecl;
1367
1368 #[test]
1369 fn workflows() {
1370 let (document, diagnostics) = Document::parse(
1371 r#"
1372version 1.1
1373
1374workflow test {
1375 input {
1376 String name
1377 Boolean do_thing
1378 }
1379
1380 output {
1381 String output = "hello, ~{name}!"
1382 }
1383
1384 if (do_thing) {
1385 call foo.my_task
1386
1387 scatter (a in [1, 2, 3]) {
1388 call my_task as my_task2 { input: a }
1389 }
1390 }
1391
1392 call my_task as my_task3 after my_task2 after my_task { input: a = 1 }
1393
1394 scatter (a in ["1", "2", "3"]) {
1395 # Do nothing
1396 }
1397
1398 meta {
1399 description: "a test"
1400 foo: null
1401 }
1402
1403 parameter_meta {
1404 name: {
1405 help: "a name to greet"
1406 }
1407 }
1408
1409 hints {
1410 foo: "bar"
1411 }
1412
1413 String x = "private"
1414}
1415"#,
1416 );
1417
1418 assert!(diagnostics.is_empty());
1419 let ast = document.ast();
1420 let ast = ast.as_v1().expect("should be a V1 AST");
1421 let workflows: Vec<_> = ast.workflows().collect();
1422 assert_eq!(workflows.len(), 1);
1423 assert_eq!(workflows[0].name().as_str(), "test");
1424
1425 let input = workflows[0]
1427 .input()
1428 .expect("workflow should have an input section");
1429 assert_eq!(input.parent().unwrap_workflow().name().as_str(), "test");
1430 let decls: Vec<_> = input.declarations().collect();
1431 assert_eq!(decls.len(), 2);
1432
1433 assert_eq!(
1435 decls[0].clone().unwrap_unbound_decl().ty().to_string(),
1436 "String"
1437 );
1438 assert_eq!(
1439 decls[0].clone().unwrap_unbound_decl().name().as_str(),
1440 "name"
1441 );
1442
1443 assert_eq!(
1445 decls[1].clone().unwrap_unbound_decl().ty().to_string(),
1446 "Boolean"
1447 );
1448 assert_eq!(
1449 decls[1].clone().unwrap_unbound_decl().name().as_str(),
1450 "do_thing"
1451 );
1452
1453 let output = workflows[0]
1455 .output()
1456 .expect("workflow should have an output section");
1457 assert_eq!(output.parent().unwrap_workflow().name().as_str(), "test");
1458 let decls: Vec<_> = output.declarations().collect();
1459 assert_eq!(decls.len(), 1);
1460
1461 assert_eq!(decls[0].ty().to_string(), "String");
1463 assert_eq!(decls[0].name().as_str(), "output");
1464 let parts: Vec<_> = decls[0]
1465 .expr()
1466 .unwrap_literal()
1467 .unwrap_string()
1468 .parts()
1469 .collect();
1470 assert_eq!(parts.len(), 3);
1471 assert_eq!(parts[0].clone().unwrap_text().as_str(), "hello, ");
1472 assert_eq!(
1473 parts[1]
1474 .clone()
1475 .unwrap_placeholder()
1476 .expr()
1477 .unwrap_name_ref()
1478 .name()
1479 .as_str(),
1480 "name"
1481 );
1482 assert_eq!(parts[2].clone().unwrap_text().as_str(), "!");
1483
1484 let statements: Vec<_> = workflows[0].statements().collect();
1486 assert_eq!(statements.len(), 4);
1487
1488 let conditional = statements[0].clone().unwrap_conditional();
1490 assert_eq!(
1491 conditional.expr().unwrap_name_ref().name().as_str(),
1492 "do_thing"
1493 );
1494
1495 let inner: Vec<_> = conditional.statements().collect();
1497 assert_eq!(inner.len(), 2);
1498
1499 let call = inner[0].clone().unwrap_call();
1501 let names = call.target().names().collect::<Vec<_>>();
1502 assert_eq!(names.len(), 2);
1503 assert_eq!(names[0].as_str(), "foo");
1504 assert_eq!(names[1].as_str(), "my_task");
1505 assert!(call.alias().is_none());
1506 assert_eq!(call.after().count(), 0);
1507 assert_eq!(call.inputs().count(), 0);
1508
1509 let scatter = inner[1].clone().unwrap_scatter();
1511 assert_eq!(scatter.variable().as_str(), "a");
1512 let elements: Vec<_> = scatter
1513 .expr()
1514 .unwrap_literal()
1515 .unwrap_array()
1516 .elements()
1517 .collect();
1518 assert_eq!(elements.len(), 3);
1519 assert_eq!(
1520 elements[0]
1521 .clone()
1522 .unwrap_literal()
1523 .unwrap_integer()
1524 .value()
1525 .unwrap(),
1526 1
1527 );
1528 assert_eq!(
1529 elements[1]
1530 .clone()
1531 .unwrap_literal()
1532 .unwrap_integer()
1533 .value()
1534 .unwrap(),
1535 2
1536 );
1537 assert_eq!(
1538 elements[2]
1539 .clone()
1540 .unwrap_literal()
1541 .unwrap_integer()
1542 .value()
1543 .unwrap(),
1544 3
1545 );
1546
1547 let inner: Vec<_> = scatter.statements().collect();
1549 assert_eq!(inner.len(), 1);
1550
1551 let call = inner[0].clone().unwrap_call();
1553 let names = call.target().names().collect::<Vec<_>>();
1554 assert_eq!(names.len(), 1);
1555 assert_eq!(names[0].as_str(), "my_task");
1556 assert_eq!(call.alias().unwrap().name().as_str(), "my_task2");
1557 assert_eq!(call.after().count(), 0);
1558 let inputs: Vec<_> = call.inputs().collect();
1559 assert_eq!(inputs.len(), 1);
1560 assert_eq!(inputs[0].name().as_str(), "a");
1561 assert!(inputs[0].expr().is_none());
1562
1563 let call = statements[1].clone().unwrap_call();
1565 assert_eq!(names.len(), 1);
1566 assert_eq!(names[0].as_str(), "my_task");
1567 assert_eq!(call.alias().unwrap().name().as_str(), "my_task3");
1568 let after: Vec<_> = call.after().collect();
1569 assert_eq!(after.len(), 2);
1570 assert_eq!(after[0].name().as_str(), "my_task2");
1571 assert_eq!(after[1].name().as_str(), "my_task");
1572 let inputs: Vec<_> = call.inputs().collect();
1573 assert_eq!(inputs.len(), 1);
1574 assert_eq!(inputs[0].name().as_str(), "a");
1575 assert_eq!(
1576 inputs[0]
1577 .expr()
1578 .unwrap()
1579 .unwrap_literal()
1580 .unwrap_integer()
1581 .value()
1582 .unwrap(),
1583 1
1584 );
1585
1586 let scatter = statements[2].clone().unwrap_scatter();
1588 assert_eq!(scatter.variable().as_str(), "a");
1589 let elements: Vec<_> = scatter
1590 .expr()
1591 .unwrap_literal()
1592 .unwrap_array()
1593 .elements()
1594 .collect();
1595 assert_eq!(elements.len(), 3);
1596 assert_eq!(
1597 elements[0]
1598 .clone()
1599 .unwrap_literal()
1600 .unwrap_string()
1601 .text()
1602 .unwrap()
1603 .as_str(),
1604 "1"
1605 );
1606 assert_eq!(
1607 elements[1]
1608 .clone()
1609 .unwrap_literal()
1610 .unwrap_string()
1611 .text()
1612 .unwrap()
1613 .as_str(),
1614 "2"
1615 );
1616 assert_eq!(
1617 elements[2]
1618 .clone()
1619 .unwrap_literal()
1620 .unwrap_string()
1621 .text()
1622 .unwrap()
1623 .as_str(),
1624 "3"
1625 );
1626
1627 let inner: Vec<_> = scatter.statements().collect();
1629 assert_eq!(inner.len(), 0);
1630
1631 let metadata = workflows[0]
1633 .metadata()
1634 .expect("workflow should have a metadata section");
1635 assert_eq!(metadata.parent().unwrap_workflow().name().as_str(), "test");
1636 let items: Vec<_> = metadata.items().collect();
1637 assert_eq!(items.len(), 2);
1638 assert_eq!(items[0].name().as_str(), "description");
1639 assert_eq!(
1640 items[0].value().unwrap_string().text().unwrap().as_str(),
1641 "a test"
1642 );
1643 assert_eq!(items[1].name().as_str(), "foo");
1644 items[1].value().unwrap_null();
1645
1646 let param_meta = workflows[0]
1648 .parameter_metadata()
1649 .expect("workflow should have a parameter metadata section");
1650 assert_eq!(
1651 param_meta.parent().unwrap_workflow().name().as_str(),
1652 "test"
1653 );
1654 let items: Vec<_> = param_meta.items().collect();
1655 assert_eq!(items.len(), 1);
1656 assert_eq!(items[0].name().as_str(), "name");
1657 let items: Vec<_> = items[0].value().unwrap_object().items().collect();
1658 assert_eq!(items.len(), 1);
1659 assert_eq!(items[0].name().as_str(), "help");
1660 assert_eq!(
1661 items[0].value().unwrap_string().text().unwrap().as_str(),
1662 "a name to greet"
1663 );
1664
1665 let hints = workflows[0]
1667 .hints()
1668 .expect("workflow should have a hints section");
1669 assert_eq!(hints.parent().name().as_str(), "test");
1670 let items: Vec<_> = hints.items().collect();
1671 assert_eq!(items.len(), 1);
1672 assert_eq!(items[0].name().as_str(), "foo");
1673 assert_eq!(
1674 items[0].value().unwrap_string().text().unwrap().as_str(),
1675 "bar"
1676 );
1677
1678 let decls: Vec<_> = workflows[0].declarations().collect();
1680 assert_eq!(decls.len(), 1);
1681
1682 assert_eq!(decls[0].ty().to_string(), "String");
1684 assert_eq!(decls[0].name().as_str(), "x");
1685 assert_eq!(
1686 decls[0]
1687 .expr()
1688 .unwrap_literal()
1689 .unwrap_string()
1690 .text()
1691 .unwrap()
1692 .as_str(),
1693 "private"
1694 );
1695
1696 #[derive(Default)]
1697 struct MyVisitor {
1698 workflows: usize,
1699 inputs: usize,
1700 outputs: usize,
1701 conditionals: usize,
1702 scatters: usize,
1703 calls: usize,
1704 metadata: usize,
1705 param_metadata: usize,
1706 unbound_decls: usize,
1707 bound_decls: usize,
1708 }
1709
1710 impl Visitor for MyVisitor {
1711 type State = ();
1712
1713 fn document(
1714 &mut self,
1715 _: &mut Self::State,
1716 _: VisitReason,
1717 _: &Document,
1718 _: SupportedVersion,
1719 ) {
1720 }
1721
1722 fn workflow_definition(
1723 &mut self,
1724 _: &mut Self::State,
1725 reason: VisitReason,
1726 _: &WorkflowDefinition,
1727 ) {
1728 if reason == VisitReason::Enter {
1729 self.workflows += 1;
1730 }
1731 }
1732
1733 fn input_section(
1734 &mut self,
1735 _: &mut Self::State,
1736 reason: VisitReason,
1737 _: &InputSection,
1738 ) {
1739 if reason == VisitReason::Enter {
1740 self.inputs += 1;
1741 }
1742 }
1743
1744 fn output_section(
1745 &mut self,
1746 _: &mut Self::State,
1747 reason: VisitReason,
1748 _: &OutputSection,
1749 ) {
1750 if reason == VisitReason::Enter {
1751 self.outputs += 1;
1752 }
1753 }
1754
1755 fn conditional_statement(
1756 &mut self,
1757 _: &mut Self::State,
1758 reason: VisitReason,
1759 _: &ConditionalStatement,
1760 ) {
1761 if reason == VisitReason::Enter {
1762 self.conditionals += 1;
1763 }
1764 }
1765
1766 fn scatter_statement(
1767 &mut self,
1768 _: &mut Self::State,
1769 reason: VisitReason,
1770 _: &ScatterStatement,
1771 ) {
1772 if reason == VisitReason::Enter {
1773 self.scatters += 1;
1774 }
1775 }
1776
1777 fn call_statement(
1778 &mut self,
1779 _: &mut Self::State,
1780 reason: VisitReason,
1781 _: &CallStatement,
1782 ) {
1783 if reason == VisitReason::Enter {
1784 self.calls += 1;
1785 }
1786 }
1787
1788 fn metadata_section(
1789 &mut self,
1790 _: &mut Self::State,
1791 reason: VisitReason,
1792 _: &MetadataSection,
1793 ) {
1794 if reason == VisitReason::Enter {
1795 self.metadata += 1;
1796 }
1797 }
1798
1799 fn parameter_metadata_section(
1800 &mut self,
1801 _: &mut Self::State,
1802 reason: VisitReason,
1803 _: &ParameterMetadataSection,
1804 ) {
1805 if reason == VisitReason::Enter {
1806 self.param_metadata += 1;
1807 }
1808 }
1809
1810 fn bound_decl(&mut self, _: &mut Self::State, reason: VisitReason, _: &BoundDecl) {
1811 if reason == VisitReason::Enter {
1812 self.bound_decls += 1;
1813 }
1814 }
1815
1816 fn unbound_decl(&mut self, _: &mut Self::State, reason: VisitReason, _: &UnboundDecl) {
1817 if reason == VisitReason::Enter {
1818 self.unbound_decls += 1;
1819 }
1820 }
1821 }
1822
1823 let mut visitor = MyVisitor::default();
1824 document.visit(&mut (), &mut visitor);
1825 assert_eq!(visitor.workflows, 1);
1826 assert_eq!(visitor.inputs, 1);
1827 assert_eq!(visitor.outputs, 1);
1828 assert_eq!(visitor.conditionals, 1);
1829 assert_eq!(visitor.scatters, 2);
1830 assert_eq!(visitor.calls, 3);
1831 assert_eq!(visitor.metadata, 1);
1832 assert_eq!(visitor.param_metadata, 1);
1833 assert_eq!(visitor.unbound_decls, 2);
1834 assert_eq!(visitor.bound_decls, 2);
1835 }
1836}