Skip to main content

wdl_format/v1/
workflow.rs

1//! Formatting for workflows.
2
3pub mod call;
4
5use wdl_ast::SyntaxKind;
6use wdl_ast::Token;
7
8use crate::PreToken;
9use crate::TokenStream;
10use crate::Trivia;
11use crate::Writable as _;
12use crate::element::FormatElement;
13
14/// Formats a [`ConditionalStatement`](wdl_ast::v1::ConditionalStatement).
15///
16/// # Panics
17///
18/// This will panic if the element does not have the expected children.
19pub fn format_conditional_statement(element: &FormatElement, stream: &mut TokenStream<PreToken>) {
20    for child in element.children().expect("conditional statement children") {
21        (&child).write(stream);
22    }
23}
24
25/// Formats a [`ConditionalStatementClause`](wdl_ast::v1::ConditionalStatementClause).
26pub fn format_conditional_statement_clause(
27    element: &FormatElement,
28    stream: &mut TokenStream<PreToken>,
29) {
30    let mut children = element
31        .children()
32        .expect("conditional statement clause children")
33        .peekable();
34
35    while let Some(el) = children.peek() {
36        // If the format element doesn't contain a token, it's not a keyword, so
37        // break.
38        let Some(token) = el.element().as_token() else {
39            break;
40        };
41
42        // Write the token if it's an `if` or an `else`.
43        match token {
44            Token::IfKeyword(_) => {
45                el.write(stream);
46            }
47            Token::ElseKeyword(_) => {
48                el.write(stream);
49            }
50            _ => break,
51        }
52
53        // Take the child token we just processed.
54        children.next();
55    }
56    stream.end_word();
57
58    let open_paren = children.next().expect("open paren");
59    assert!(open_paren.element().kind() == SyntaxKind::OpenParen);
60    (&open_paren).write(stream);
61
62    for child in children.by_ref() {
63        (&child).write(stream);
64        if child.element().kind() == SyntaxKind::CloseParen {
65            stream.end_word();
66            break;
67        }
68    }
69
70    let open_brace = children.next().expect("open brace");
71    assert!(open_brace.element().kind() == SyntaxKind::OpenBrace);
72    (&open_brace).write(stream);
73    stream.increment_indent();
74
75    for child in children {
76        if child.element().kind() == SyntaxKind::CloseBrace {
77            stream.decrement_indent();
78        }
79        (&child).write(stream);
80    }
81    stream.end_line();
82}
83
84/// Formats a [`ScatterStatement`](wdl_ast::v1::ScatterStatement).
85///
86/// # Panics
87///
88/// This will panic if the element does not have the expected children.
89pub fn format_scatter_statement(element: &FormatElement, stream: &mut TokenStream<PreToken>) {
90    let mut children = element.children().expect("scatter statement children");
91
92    let scatter_keyword = children.next().expect("scatter keyword");
93    assert!(scatter_keyword.element().kind() == SyntaxKind::ScatterKeyword);
94    (&scatter_keyword).write(stream);
95    stream.end_word();
96
97    let open_paren = children.next().expect("open paren");
98    assert!(open_paren.element().kind() == SyntaxKind::OpenParen);
99    (&open_paren).write(stream);
100
101    let variable = children.next().expect("scatter variable");
102    assert!(variable.element().kind() == SyntaxKind::Ident);
103    (&variable).write(stream);
104    stream.end_word();
105
106    let in_keyword = children.next().expect("in keyword");
107    assert!(in_keyword.element().kind() == SyntaxKind::InKeyword);
108    (&in_keyword).write(stream);
109    stream.end_word();
110
111    for child in children.by_ref() {
112        (&child).write(stream);
113        if child.element().kind() == SyntaxKind::CloseParen {
114            stream.end_word();
115            break;
116        }
117    }
118
119    let open_brace = children.next().expect("open brace");
120    assert!(open_brace.element().kind() == SyntaxKind::OpenBrace);
121    (&open_brace).write(stream);
122    stream.end_line();
123    stream.increment_indent();
124
125    for child in children {
126        if child.element().kind() == SyntaxKind::CloseBrace {
127            stream.decrement_indent();
128        }
129        (&child).write(stream);
130    }
131    stream.end_line();
132}
133
134/// Formats a [`WorkflowDefinition`](wdl_ast::v1::WorkflowDefinition).
135///
136/// # Panics
137///
138/// This will panic if the element does not have the expected children.
139pub fn format_workflow_definition(element: &FormatElement, stream: &mut TokenStream<PreToken>) {
140    let mut children = element.children().expect("workflow definition children");
141
142    stream.ignore_trailing_blank_lines();
143
144    let workflow_keyword = children.next().expect("workflow keyword");
145    assert!(workflow_keyword.element().kind() == SyntaxKind::WorkflowKeyword);
146    (&workflow_keyword).write(stream);
147    stream.end_word();
148
149    let name = children.next().expect("workflow name");
150    assert!(name.element().kind() == SyntaxKind::Ident);
151    (&name).write(stream);
152    stream.end_word();
153
154    let open_brace = children.next().expect("open brace");
155    assert!(open_brace.element().kind() == SyntaxKind::OpenBrace);
156    (&open_brace).write(stream);
157    stream.increment_indent();
158
159    let mut meta = None;
160    let mut parameter_meta = None;
161    let mut input = None;
162    let mut body = Vec::new();
163    let mut output = None;
164    let mut hints = None;
165    let mut close_brace = None;
166
167    for child in children {
168        match child.element().kind() {
169            SyntaxKind::MetadataSectionNode => {
170                meta = Some(child.clone());
171            }
172            SyntaxKind::ParameterMetadataSectionNode => {
173                parameter_meta = Some(child.clone());
174            }
175            SyntaxKind::InputSectionNode => {
176                input = Some(child.clone());
177            }
178            SyntaxKind::BoundDeclNode => {
179                body.push(child.clone());
180            }
181            SyntaxKind::CallStatementNode => {
182                body.push(child.clone());
183            }
184            SyntaxKind::ConditionalStatementNode => {
185                body.push(child.clone());
186            }
187            SyntaxKind::ScatterStatementNode => {
188                body.push(child.clone());
189            }
190            SyntaxKind::OutputSectionNode => {
191                output = Some(child.clone());
192            }
193            SyntaxKind::WorkflowHintsSectionNode => {
194                hints = Some(child.clone());
195            }
196            SyntaxKind::CloseBrace => {
197                close_brace = Some(child.clone());
198            }
199            _ => {
200                unreachable!(
201                    "unexpected child in workflow definition: {:?}",
202                    child.element().kind()
203                );
204            }
205        }
206    }
207
208    if let Some(meta) = meta {
209        (&meta).write(stream);
210        stream.blank_line();
211    }
212
213    if let Some(parameter_meta) = parameter_meta {
214        (&parameter_meta).write(stream);
215        stream.blank_line();
216    }
217
218    if let Some(input) = input {
219        (&input).write(stream);
220        stream.blank_line();
221    }
222
223    stream.allow_blank_lines();
224    for child in body {
225        (&child).write(stream);
226    }
227    stream.ignore_trailing_blank_lines();
228    stream.blank_line();
229
230    if let Some(output) = output {
231        (&output).write(stream);
232        stream.blank_line();
233    }
234
235    if let Some(hints) = hints {
236        (&hints).write(stream);
237        stream.blank_line();
238    }
239
240    stream.trim_while(|t| matches!(t, PreToken::BlankLine | PreToken::Trivia(Trivia::BlankLine)));
241
242    stream.decrement_indent();
243    (&close_brace.expect("workflow close brace")).write(stream);
244    stream.end_line();
245}
246
247/// Formats a [`WorkflowHintsArray`](wdl_ast::v1::WorkflowHintsArray).
248///
249/// # Panics
250///
251/// This will panic if the element does not have the expected children.
252pub fn format_workflow_hints_array(element: &FormatElement, stream: &mut TokenStream<PreToken>) {
253    let mut children = element.children().expect("workflow hints array children");
254
255    let open_bracket = children.next().expect("open bracket");
256    assert!(open_bracket.element().kind() == SyntaxKind::OpenBracket);
257    (&open_bracket).write(stream);
258    stream.increment_indent();
259
260    let mut items = Vec::new();
261    let mut commas = Vec::new();
262    let mut close_bracket = None;
263
264    for child in children {
265        match child.element().kind() {
266            SyntaxKind::Comma => {
267                commas.push(child.clone());
268            }
269            SyntaxKind::CloseBracket => {
270                close_bracket = Some(child.clone());
271            }
272            _ => {
273                items.push(child.clone());
274            }
275        }
276    }
277
278    let mut commas = commas.into_iter();
279    for item in items {
280        (&item).write(stream);
281        match commas.next() {
282            Some(comma) => {
283                (&comma).write(stream);
284            }
285            _ => {
286                stream.push_literal(",".to_string(), SyntaxKind::Comma);
287            }
288        }
289        stream.end_line();
290    }
291
292    stream.decrement_indent();
293    (&close_bracket.expect("workflow hints array close bracket")).write(stream);
294}
295
296/// Formats a [`WorkflowHintsItem`](wdl_ast::v1::WorkflowHintsItem).
297///
298/// # Panics
299///
300/// This will panic if the element does not have the expected children.
301pub fn format_workflow_hints_item(element: &FormatElement, stream: &mut TokenStream<PreToken>) {
302    let mut children = element.children().expect("workflow hints item children");
303
304    let key = children.next().expect("workflow hints item key");
305    assert!(key.element().kind() == SyntaxKind::Ident);
306    (&key).write(stream);
307
308    let colon = children.next().expect("workflow hints item colon");
309    assert!(colon.element().kind() == SyntaxKind::Colon);
310    (&colon).write(stream);
311    stream.end_word();
312
313    let value = children.next().expect("workflow hints item value");
314    (&value).write(stream);
315
316    stream.end_line();
317}
318
319/// Formats a [`WorkflowHintsObjectItem`](wdl_ast::v1::WorkflowHintsObjectItem).
320///
321/// # Panics
322///
323/// This will panic if the element does not have the expected children.
324pub fn format_workflow_hints_object_item(
325    element: &FormatElement,
326    stream: &mut TokenStream<PreToken>,
327) {
328    let mut children = element
329        .children()
330        .expect("workflow hints object item children");
331
332    let key = children.next().expect("workflow hints object item key");
333    assert!(key.element().kind() == SyntaxKind::Ident);
334    (&key).write(stream);
335
336    let colon = children.next().expect("workflow hints object item colon");
337    assert!(colon.element().kind() == SyntaxKind::Colon);
338    (&colon).write(stream);
339    stream.end_word();
340
341    let value = children.next().expect("workflow hints object item value");
342    (&value).write(stream);
343
344    stream.end_line();
345}
346
347/// Formats a [`WorkflowHintsObject`](wdl_ast::v1::WorkflowHintsObject).
348///
349/// # Panics
350///
351/// This will panic if the element does not have the expected children.
352pub fn format_workflow_hints_object(element: &FormatElement, stream: &mut TokenStream<PreToken>) {
353    let mut children = element.children().expect("workflow hints object children");
354
355    let open_brace = children.next().expect("open brace");
356    assert!(open_brace.element().kind() == SyntaxKind::OpenBrace);
357    (&open_brace).write(stream);
358    stream.increment_indent();
359
360    for child in children {
361        if child.element().kind() == SyntaxKind::CloseBrace {
362            stream.decrement_indent();
363        }
364        (&child).write(stream);
365        stream.end_line();
366    }
367}
368
369/// Formats a [`WorkflowHintsSection`](wdl_ast::v1::WorkflowHintsSection).
370///
371/// # Panics
372///
373/// This will panic if the element does not have the expected children.
374pub fn format_workflow_hints_section(element: &FormatElement, stream: &mut TokenStream<PreToken>) {
375    let mut children = element.children().expect("workflow hints section children");
376
377    let hints_keyword = children.next().expect("hints keyword");
378    assert!(hints_keyword.element().kind() == SyntaxKind::HintsKeyword);
379    (&hints_keyword).write(stream);
380    stream.end_word();
381
382    let open_brace = children.next().expect("open brace");
383    assert!(open_brace.element().kind() == SyntaxKind::OpenBrace);
384    (&open_brace).write(stream);
385    stream.increment_indent();
386
387    for child in children {
388        if child.element().kind() == SyntaxKind::CloseBrace {
389            stream.decrement_indent();
390        }
391        (&child).write(stream);
392        stream.end_line();
393    }
394}