Skip to content

Commit 2f8c46d

Browse files
[WX-1460] WDL 1.1 Struct Literal Parsing (#7391)
Co-authored-by: Janet Gainer-Dewar <jdewar@broadinstitute.org>
1 parent 027de62 commit 2f8c46d

File tree

42 files changed

+2666
-1938
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+2666
-1938
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name: struct_literal
2+
testFormat: workflowsuccess
3+
4+
files {
5+
workflow: struct_literal/struct_literal.wdl
6+
}
7+
8+
metadata {
9+
workflowName: struct_literal
10+
status: Succeeded
11+
"outputs.struct_literal.out": 44
12+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
version development-1.1
2+
3+
struct Plant {
4+
String color
5+
Int id
6+
}
7+
8+
struct Fungi {
9+
File fungiFile
10+
}
11+
12+
13+
struct Animal {
14+
Plant jacket
15+
Fungi hat
16+
}
17+
18+
task a {
19+
input {
20+
Plant in_plant_literal = Plant{color: "red", id: 44}
21+
}
22+
23+
command {
24+
echo "${in_plant_literal.id}"
25+
}
26+
27+
output {
28+
Animal out_animal = Animal{jacket: Plant{color: "green", id: 10}, hat: Fungi{fungiFile: stdout()}}
29+
}
30+
31+
runtime {
32+
docker: "ubuntu:latest"
33+
}
34+
35+
meta {
36+
volatile: true
37+
}
38+
}
39+
40+
task b {
41+
input {
42+
Animal in_animal
43+
}
44+
45+
command {
46+
cat ${in_animal.hat.fungiFile}
47+
}
48+
49+
output {
50+
Int out = read_int(stdout())
51+
}
52+
53+
runtime {
54+
docker: "ubuntu:latest"
55+
}
56+
57+
meta {
58+
volatile: true
59+
}
60+
}
61+
62+
workflow struct_literal {
63+
call a
64+
call b {input: in_animal=a.out_animal}
65+
output {
66+
Int out = b.out
67+
}
68+
}

wdl/model/draft3/src/main/scala/wdl/model/draft3/elements/ExpressionElement.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ object ExpressionElement {
3333

3434
final case class KvPair(key: String, value: ExpressionElement)
3535
final case class ObjectLiteral(elements: Map[String, ExpressionElement]) extends ExpressionElement
36+
final case class StructLiteral(structTypeName: String, elements: Map[String, ExpressionElement])
37+
extends ExpressionElement
3638
final case class ArrayLiteral(elements: Seq[ExpressionElement]) extends ExpressionElement
3739
final case class MapLiteral(elements: Map[ExpressionElement, ExpressionElement]) extends ExpressionElement
3840
final case class PairLiteral(left: ExpressionElement, right: ExpressionElement) extends ExpressionElement

wdl/transforms/biscayne/src/main/java/wdl/biscayne/parser/WdlParser.java

Lines changed: 983 additions & 961 deletions
Large diffs are not rendered by default.
Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
11
2023-03-16
22
Synced grammar from OpenWDL `development` version, which is actually development of 2.0. There is no 1.1 Hermes grammar, develop it here.
33
Changed version declaration to `development1_1`.
4-
This disallows `version 1.1` workflows to run with incomplete support. Once development is finished, change to `1.1`.
4+
This disallows `version 1.1` workflows to run with incomplete support. Once development is finished, change to `1.1`.
5+
6+
2024-02-28
7+
When changing the grammar file, generate a new parser by:
8+
- changing current working directory to cromwell/wdl/transforms/biscayne
9+
- running: hermes generate src/main/resources/grammar.hgr \
10+
--language=java \
11+
--directory=src/main/java \
12+
--name=wdl \
13+
--java-package=wdl.biscayne.parser \
14+
--java-use-apache-commons --java-imports=org.apache.commons.lang3.StringEscapeUtils \
15+
--header

wdl/transforms/biscayne/src/main/resources/grammar.hgr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ grammar {
401401
(*:unary) $e = :not $e -> LogicalNot(expression=$1)
402402
(-:unary) $e = :plus $e -> UnaryPlus(expression=$1)
403403
(-:unary) $e = :dash $e -> UnaryNegation(expression=$1)
404+
(*:left) $e = :identifier <=> :lbrace list($object_kv, :comma) :rbrace -> StructLiteral(name=$0, map=$2)
404405
(*:left) $e = :identifier <=> :lparen list($e, :comma) :rparen -> FunctionCall(name=$0, params=$2)
405406
(*:left) $e = $e <=> :lsquare $e :rsquare -> ArrayOrMapLookup(lhs=$0, rhs=$2)
406407
(*:left) $e = $e <=> :dot :identifier -> MemberAccess(value=$0, member=$2)

wdl/transforms/biscayne/src/main/scala/wdl/transforms/biscayne/linking/expression/consumed/BiscayneExpressionValueConsumers.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,14 @@ object BiscayneExpressionValueConsumers {
105105
// None literals consume no values:
106106
Set.empty[UnlinkedConsumedValueHook]
107107
}
108+
109+
implicit val structLiteralExpressionValueConsumer: ExpressionValueConsumer[StructLiteral] =
110+
new ExpressionValueConsumer[StructLiteral] {
111+
override def expressionConsumedValueHooks(a: StructLiteral)(implicit
112+
expressionValueConsumer: ExpressionValueConsumer[ExpressionElement]
113+
): Set[UnlinkedConsumedValueHook] =
114+
a.elements.values
115+
.flatMap(element => expressionValueConsumer.expressionConsumedValueHooks(element)(expressionValueConsumer))
116+
.toSet
117+
}
108118
}

wdl/transforms/biscayne/src/main/scala/wdl/transforms/biscayne/linking/expression/consumed/consumed.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ package object consumed {
2424

2525
case a: StringExpression => a.expressionConsumedValueHooks(expressionValueConsumer)
2626
case a: ObjectLiteral => a.expressionConsumedValueHooks(expressionValueConsumer)
27+
case a: StructLiteral => a.expressionConsumedValueHooks(expressionValueConsumer)
2728
case a: PairLiteral => a.expressionConsumedValueHooks(expressionValueConsumer)
2829
case a: ArrayLiteral => a.expressionConsumedValueHooks(expressionValueConsumer)
2930
case a: MapLiteral => a.expressionConsumedValueHooks(expressionValueConsumer)

wdl/transforms/biscayne/src/main/scala/wdl/transforms/biscayne/linking/expression/files/BiscayneFileEvaluators.scala

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package wdl.transforms.biscayne.linking.expression.files
22

3+
import cats.implicits.{catsSyntaxValidatedId, toTraverseOps}
4+
import common.validation.ErrorOr.ErrorOr
5+
import wdl.model.draft3.elements.ExpressionElement
36
import wdl.model.draft3.elements.ExpressionElement.{
47
AsMap,
58
AsPairs,
@@ -10,16 +13,20 @@ import wdl.model.draft3.elements.ExpressionElement.{
1013
Quote,
1114
Sep,
1215
SQuote,
16+
StructLiteral,
1317
SubPosix,
1418
Suffix,
1519
Unzip
1620
}
17-
import wdl.model.draft3.graph.expression.FileEvaluator
21+
import wdl.model.draft3.graph.expression.{FileEvaluator, ValueEvaluator}
1822
import wdl.transforms.base.linking.expression.files.EngineFunctionEvaluators.{
1923
threeParameterFunctionPassthroughFileEvaluator,
2024
twoParameterFunctionPassthroughFileEvaluator
2125
}
2226
import wdl.transforms.base.linking.expression.files.EngineFunctionEvaluators.singleParameterPassthroughFileEvaluator
27+
import wom.expression.IoFunctionSet
28+
import wom.types.{WomCompositeType, WomType}
29+
import wom.values.{WomFile, WomValue}
2330

2431
object BiscayneFileEvaluators {
2532

@@ -39,4 +46,38 @@ object BiscayneFileEvaluators {
3946
implicit val maxFunctionEvaluator: FileEvaluator[Max] = twoParameterFunctionPassthroughFileEvaluator[Max]
4047

4148
implicit val unzipFunctionEvaluator: FileEvaluator[Unzip] = singleParameterPassthroughFileEvaluator
49+
50+
implicit val structLiteralEvaluator: FileEvaluator[StructLiteral] = new FileEvaluator[StructLiteral] {
51+
override def predictFilesNeededToEvaluate(a: StructLiteral,
52+
inputs: Map[String, WomValue],
53+
ioFunctionSet: IoFunctionSet,
54+
coerceTo: WomType
55+
)(implicit
56+
fileEvaluator: FileEvaluator[ExpressionElement],
57+
valueEvaluator: ValueEvaluator[ExpressionElement]
58+
): ErrorOr[Set[WomFile]] = {
59+
def filesInObjectField(fieldAndWomTypeTuple: (String, WomType)): ErrorOr[Set[WomFile]] = {
60+
val (field, womType) = fieldAndWomTypeTuple
61+
a.elements.get(field) match {
62+
case Some(fieldElement) =>
63+
fileEvaluator.predictFilesNeededToEvaluate(fieldElement, inputs, ioFunctionSet, womType)(fileEvaluator,
64+
valueEvaluator
65+
)
66+
case None => s"Invalid assignment to struct. Required field $field was not specified.".invalidNel
67+
}
68+
}
69+
70+
coerceTo match {
71+
case WomCompositeType(mapping, _) => mapping.toList.traverse(filesInObjectField).map(_.flatten.toSet)
72+
case _ =>
73+
a.elements.values.toList
74+
.traverse(
75+
fileEvaluator.evaluateFilesNeededToEvaluate(_, inputs, ioFunctionSet, coerceTo)(fileEvaluator,
76+
valueEvaluator
77+
)
78+
)
79+
.map(_.toSet.flatten)
80+
}
81+
}
82+
}
4283
}

wdl/transforms/biscayne/src/main/scala/wdl/transforms/biscayne/linking/expression/files/files.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import wom.expression.IoFunctionSet
1616
import wom.types.WomType
1717
import wom.values.{WomFile, WomValue}
1818
import wdl.transforms.biscayne.linking.expression.files.BiscayneFileEvaluators._
19-
2019
package object files {
2120

2221
implicit val expressionFileEvaluator: FileEvaluator[ExpressionElement] = new FileEvaluator[ExpressionElement] {
@@ -37,6 +36,8 @@ package object files {
3736
a.predictFilesNeededToEvaluate(inputs, ioFunctionSet, coerceTo)(fileEvaluator, valueEvaluator)
3837
case a: ObjectLiteral =>
3938
a.predictFilesNeededToEvaluate(inputs, ioFunctionSet, coerceTo)(fileEvaluator, valueEvaluator)
39+
case a: StructLiteral =>
40+
a.predictFilesNeededToEvaluate(inputs, ioFunctionSet, coerceTo)(fileEvaluator, valueEvaluator)
4041
case a: MapLiteral =>
4142
a.predictFilesNeededToEvaluate(inputs, ioFunctionSet, coerceTo)(fileEvaluator, valueEvaluator)
4243
case a: ArrayLiteral =>

0 commit comments

Comments
 (0)