diff --git a/build.sbt b/build.sbt index 4464ff9d0fa..8aba7fa7433 100644 --- a/build.sbt +++ b/build.sbt @@ -3,7 +3,7 @@ import sbtassembly.Plugin._ import sbtrelease.ReleasePlugin._ name := "cromwell" -version := "0.8" +version := "0.9" organization := "org.broadinstitute" scalaVersion := "2.11.7" diff --git a/src/main/java/cromwell/parser/WdlParser.java b/src/main/java/cromwell/parser/WdlParser.java index 583bf93e412..473b01dca90 100644 --- a/src/main/java/cromwell/parser/WdlParser.java +++ b/src/main/java/cromwell/parser/WdlParser.java @@ -1,4 +1,17 @@ +/* + * This file was generated by Hermes Parser Generator on Fri Aug 14 14:27:20 2015 + * + * Hermes command: hermes generate src/main/resources/grammar.hgr --language=java --directory=src/main/java --name=wdl --java-package=cromwell.parser --java-use-apache-commons --header + * Run from: ../../.. (relative to this file) + * Hermes version: hermes-parser 2.0rc1 + * + * !!! DO NOT CHANGE THIS FILE DIRECTLY !!! + * + * If you wish to change something in this file, either change the grammar and + * re-generate this file, or change the templates in Hermes. See the Hermes + * repository: http://github.com/scottfrazer/hermes + */ package cromwell.parser; import java.util.*; import java.io.IOException; @@ -493,63 +506,61 @@ public interface TerminalIdentifier { } public enum WdlTerminalIdentifier implements TerminalIdentifier { TERMINAL_CALL(0, "call"), - TERMINAL_TASK(1, "task"), - TERMINAL_WORKFLOW(2, "workflow"), - TERMINAL_RAW_CMD_START(3, "raw_cmd_start"), - TERMINAL_CMD_PARAM_START(4, "cmd_param_start"), - TERMINAL_TYPE(5, "type"), - TERMINAL_LT(6, "lt"), - TERMINAL_LBRACE(7, "lbrace"), - TERMINAL_GT(8, "gt"), - TERMINAL_COMMA(9, "comma"), - TERMINAL_NOT_EQUAL(10, "not_equal"), - TERMINAL_TYPE_E(11, "type_e"), - TERMINAL_CMD_PART(12, "cmd_part"), - TERMINAL_DOUBLE_PIPE(13, "double_pipe"), - TERMINAL_LPAREN(14, "lparen"), - TERMINAL_AS(15, "as"), - TERMINAL_CMD_ATTR_HINT(16, "cmd_attr_hint"), - TERMINAL_ASTERISK(17, "asterisk"), - TERMINAL_E(18, "e"), - TERMINAL_DQUOTE_STRING(19, "dquote_string"), - TERMINAL_RAW_COMMAND(20, "raw_command"), - TERMINAL_OUTPUT(21, "output"), - TERMINAL_CMD_PARAM_END(22, "cmd_param_end"), - TERMINAL_WHILE(23, "while"), - TERMINAL_RPAREN(24, "rparen"), - TERMINAL_SCATTER(25, "scatter"), - TERMINAL_OBJECT(26, "object"), - TERMINAL_IMPORT(27, "import"), - TERMINAL_GTEQ(28, "gteq"), - TERMINAL_FLOAT(29, "float"), - TERMINAL_PARAMETER_META(30, "parameter_meta"), - TERMINAL_COLON(31, "colon"), - TERMINAL_BOOLEAN(32, "boolean"), - TERMINAL_NOT(33, "not"), - TERMINAL_RAW_CMD_END(34, "raw_cmd_end"), - TERMINAL_RUNTIME(35, "runtime"), - TERMINAL_INPUT(36, "input"), - TERMINAL_PERCENT(37, "percent"), - TERMINAL_IDENTIFIER(38, "identifier"), - TERMINAL_QMARK(39, "qmark"), - TERMINAL_SLASH(40, "slash"), - TERMINAL_STRING(41, "string"), - TERMINAL_IF(42, "if"), - TERMINAL_NS_IDENTIFIER(43, "ns_identifier"), - TERMINAL_LTEQ(44, "lteq"), - TERMINAL_DOT(45, "dot"), - TERMINAL_RSQUARE(46, "rsquare"), - TERMINAL_META(47, "meta"), - TERMINAL_SQUOTE_STRING(48, "squote_string"), - TERMINAL_PLUS(49, "plus"), - TERMINAL_DOUBLE_EQUAL(50, "double_equal"), - TERMINAL_LSQUARE(51, "lsquare"), - TERMINAL_IN(52, "in"), - TERMINAL_RBRACE(53, "rbrace"), - TERMINAL_EQUAL(54, "equal"), - TERMINAL_INTEGER(55, "integer"), - TERMINAL_DOUBLE_AMPERSAND(56, "double_ampersand"), - TERMINAL_DASH(57, "dash"), + TERMINAL_FLOAT(1, "float"), + TERMINAL_PERCENT(2, "percent"), + TERMINAL_SCATTER(3, "scatter"), + TERMINAL_RAW_COMMAND(4, "raw_command"), + TERMINAL_GTEQ(5, "gteq"), + TERMINAL_LPAREN(6, "lparen"), + TERMINAL_INTEGER(7, "integer"), + TERMINAL_OUTPUT(8, "output"), + TERMINAL_INPUT(9, "input"), + TERMINAL_STRING(10, "string"), + TERMINAL_CMD_ATTR_HINT(11, "cmd_attr_hint"), + TERMINAL_LTEQ(12, "lteq"), + TERMINAL_NOT_EQUAL(13, "not_equal"), + TERMINAL_GT(14, "gt"), + TERMINAL_DASH(15, "dash"), + TERMINAL_RPAREN(16, "rparen"), + TERMINAL_META(17, "meta"), + TERMINAL_IDENTIFIER(18, "identifier"), + TERMINAL_QMARK(19, "qmark"), + TERMINAL_PLUS(20, "plus"), + TERMINAL_DOT(21, "dot"), + TERMINAL_ASTERISK(22, "asterisk"), + TERMINAL_CMD_PARAM_END(23, "cmd_param_end"), + TERMINAL_TYPE(24, "type"), + TERMINAL_RUNTIME(25, "runtime"), + TERMINAL_TASK(26, "task"), + TERMINAL_SLASH(27, "slash"), + TERMINAL_CMD_PART(28, "cmd_part"), + TERMINAL_PARAMETER_META(29, "parameter_meta"), + TERMINAL_DOUBLE_AMPERSAND(30, "double_ampersand"), + TERMINAL_DOUBLE_EQUAL(31, "double_equal"), + TERMINAL_IMPORT(32, "import"), + TERMINAL_LT(33, "lt"), + TERMINAL_COMMA(34, "comma"), + TERMINAL_LSQUARE(35, "lsquare"), + TERMINAL_E(36, "e"), + TERMINAL_OBJECT(37, "object"), + TERMINAL_AS(38, "as"), + TERMINAL_IF(39, "if"), + TERMINAL_RBRACE(40, "rbrace"), + TERMINAL_LBRACE(41, "lbrace"), + TERMINAL_WHILE(42, "while"), + TERMINAL_TYPE_E(43, "type_e"), + TERMINAL_DOUBLE_PIPE(44, "double_pipe"), + TERMINAL_NOT(45, "not"), + TERMINAL_EQUAL(46, "equal"), + TERMINAL_RSQUARE(47, "rsquare"), + TERMINAL_COLON(48, "colon"), + TERMINAL_FQN(49, "fqn"), + TERMINAL_RAW_CMD_START(50, "raw_cmd_start"), + TERMINAL_CMD_PARAM_START(51, "cmd_param_start"), + TERMINAL_RAW_CMD_END(52, "raw_cmd_end"), + TERMINAL_WORKFLOW(53, "workflow"), + TERMINAL_IN(54, "in"), + TERMINAL_BOOLEAN(55, "boolean"), END_SENTINAL(-3, "END_SENTINAL"); private final int id; private final String string; @@ -562,757 +573,896 @@ public enum WdlTerminalIdentifier implements TerminalIdentifier { } /* table[nonterminal][terminal] = rule */ private static final int[][] table = { - { -1, -1, -1, -1, -1, 51, -1, -1, -1, -1, -1, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, 15, -1, -1, -1, -1, -1, 15, -1, -1, -1, -1, -1, -1, -1, -1, 18, 18, -1, -1, -1, -1, -1, -1, -1, -1, 18, -1, -1, -1, -1, 18, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, 12, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 77, -1, -1, -1, -1, 77, -1, 77, -1, -1, -1, 77, -1, -1, -1, 76, -1, -1, -1, -1, -1, -1, -1, 77, -1, 77, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 77, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 77, -1, -1, -1, -1 }, - { -1, 10, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 59, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 71, -1, -1, -1, -1, 72, -1, -1, -1, -1, -1, 72, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, -1, 75, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 74, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 93, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 60, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 63, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, 131, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 132, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 82, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 83, -1, -1, -1, -1 }, - { 80, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, 98, -1, -1, -1, -1, -1, 98, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 81, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 99, -1, -1, -1 }, - { -1, -1, -1, -1, 46, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, 64, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, 101, -1, -1, -1, -1, -1, 101, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 104, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 123, -1, -1, -1, 123, 123, -1, -1, -1, -1, 126, -1, 123, -1, -1, 123, -1, -1, 123, 123, -1, -1, -1, -1, 123, -1, -1, 123, -1, -1, -1, -1, 126, -1, 123, 123, -1, 123, -1, -1, -1, 123, -1, 123 }, - { -1, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, -1, -1, -1, -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, 35, -1, -1, -1, -1, -1, -1, -1, 34, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 61, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 90, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, 56, -1, -1, -1, -1, -1, 56, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 79, -1, -1, -1, -1, 79, -1, 78, -1, -1, -1, 79, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 79, -1, 79, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 79, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 79, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 38, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, 3, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, 30, -1, -1, -1, -1, -1, -1, -1, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 89, -1, 86, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 89, -1, -1, -1, -1 }, - { -1, -1, 70, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 39, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 50, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 48, -1, -1, -1, -1, -1, -1, -1, -1, -1, 49, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 94, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 67, -1, -1, -1, -1, 67, -1, -1, -1, -1, -1, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 67, -1, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 68, -1, -1, -1, -1 }, - { -1, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 24, 25, -1, -1, -1, -1, -1, -1, -1, -1, 27, -1, -1, -1, -1, 26, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 28, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 91, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, 102, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 103, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 66, -1, -1, -1, -1, 66, -1, -1, -1, -1, -1, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 66, -1, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 69, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 19, 19, -1, -1, -1, -1, -1, -1, -1, -1, 19, -1, -1, -1, -1, 19, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 19, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 100, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 20, 20, -1, -1, -1, -1, -1, -1, -1, -1, 20, -1, -1, -1, -1, 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 20, -1, -1, -1, -1, -1, 21, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, 124, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 125, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 125, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, 41, -1, -1, -1, -1, -1, 41, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 40, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 95, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, 29, -1, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, 8, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 130, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 133, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, 16, -1, -1, -1, -1, -1, 16, -1, -1, -1, -1, -1, -1, -1, -1, 17, 17, -1, -1, -1, -1, -1, -1, -1, -1, 17, -1, -1, -1, -1, 17, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 88, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, 52, -1, -1, -1, -1, -1, 52, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 53, -1, -1, -1, -1 }, - { 97, -1, -1, -1, -1, 97, -1, -1, -1, -1, -1, 97, -1, -1, -1, -1, -1, -1, -1, -1, 97, 97, -1, 97, -1, 97, -1, -1, -1, -1, 97, -1, -1, -1, -1, 97, 97, -1, -1, -1, -1, -1, 97, -1, -1, -1, -1, 97, -1, -1, -1, -1, -1, 97, 96, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, 18, -1, -1, -1, 18, 18, -1, -1, -1, -1, -1, -1, -1, 18, -1, -1, -1, -1, -1, -1, 15, 18, -1, -1, -1, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 70, -1, -1 }, + { 81, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, 82, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 101, -1, -1, -1, -1, -1, -1 }, + { -1, 129, -1, -1, -1, -1, 129, 129, -1, -1, 129, -1, -1, -1, -1, 129, 132, -1, 129, -1, 129, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 129, 129, 129, -1, -1, -1, 129, -1, -1, -1, 129, -1, 132, -1, -1, -1, -1, -1, -1, -1, 129 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 29, 32, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 56, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, 89, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 88, -1, -1, -1, -1, -1, 89, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 40, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 93, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 30, 31, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 71, -1, -1, 75, -1, -1, -1, -1, 76, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 72, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 74, -1, -1, 73, 72, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 41, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 34, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 35, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 86, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 99, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 100, -1, -1, -1, -1, -1, 100, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 95, -1, -1, -1, -1, -1, 96, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 63, 64, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 9, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 49, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, 142, -1, -1, -1, -1, 142, 142, -1, -1, 142, -1, -1, -1, -1, 142, -1, -1, 142, -1, 142, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 142, 142, 142, -1, -1, 145, 142, -1, -1, -1, 142, -1, -1, -1, -1, -1, -1, -1, -1, -1, 142 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 108, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 109, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, -1, -1, -1, -1, -1, 12, -1, -1, -1, -1, -1, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 48, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, 98, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 103, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, 46, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 52, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 106, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 67, -1, -1, 67, -1, -1, -1, -1, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 67, 68, -1, 67, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, 91, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, -1, -1, -1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1 }, + { -1, -1, -1, -1, 17, -1, -1, -1, 17, 17, -1, -1, -1, -1, -1, -1, -1, 17, -1, -1, -1, -1, -1, -1, 16, 17, -1, -1, -1, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 16, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, 38, -1, -1, -1, -1, 38, 38, -1, -1, 38, 37, -1, -1, -1, 38, -1, -1, 38, -1, 38, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 38, 38, 38, -1, -1, -1, 38, -1, -1, -1, 38, -1, -1, -1, -1, -1, -1, -1, -1, -1, 38 }, + { -1, 65, -1, -1, -1, -1, 65, 65, -1, -1, 65, -1, -1, -1, -1, 65, -1, -1, 65, -1, 65, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 65, 65, -1, -1, -1, 65, -1, -1, -1, 65, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65 }, + { -1, -1, -1, -1, 19, -1, -1, -1, 19, -1, -1, -1, -1, -1, -1, -1, -1, 19, -1, -1, -1, -1, -1, -1, -1, 19, -1, -1, -1, 19, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 45, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 78, -1, -1, 78, -1, -1, -1, -1, 78, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 78, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 77, 78, 78, 78, 78, 78, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 60, -1, -1, 60, 60, -1, -1, -1, 60, 60, -1, -1, -1, -1, -1, -1, -1, 60, -1, -1, -1, -1, -1, -1, 60, 60, -1, -1, -1, 60, -1, -1, -1, -1, -1, -1, -1, -1, -1, 60, 60, -1, 60, 60, -1, -1, 59, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, 90, -1, -1, -1, -1, -1, -1, -1, -1, 87, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 90, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 80, -1, -1, 80, -1, -1, -1, -1, 80, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 80, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 80, 80, 79, 80, 80, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, 20, -1, -1, -1, 20, -1, -1, -1, -1, -1, -1, -1, -1, 20, -1, -1, -1, -1, -1, -1, -1, 20, -1, -1, -1, 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 21, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, 105, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 143, -1, -1, -1, -1, -1, 144, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, 39, -1, -1, -1, -1, 39, 39, -1, -1, 39, 36, -1, -1, -1, 39, -1, -1, 39, -1, 39, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 39, 39, 39, -1, -1, -1, 39, -1, -1, -1, 39, -1, -1, -1, -1, -1, -1, -1, -1, -1, 39 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 136, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 139, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 97, -1, -1, -1, -1, -1, -1, -1, -1, 94, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 58, 57, 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 102, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 66, -1, -1, 66, -1, -1, -1, -1, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 66, 69, -1, 66, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, 24, -1, -1, -1, 25, -1, -1, -1, -1, -1, -1, -1, -1, 28, -1, -1, -1, -1, -1, -1, -1, 26, -1, -1, -1, 27, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, -1, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 107, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 107, -1, -1, -1, 110, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 61, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 61, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 104, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, 83, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 50, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 137, -1, -1, -1, -1, -1, 138, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 131, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 130, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 131, -1, -1, -1, -1, -1, -1, -1, -1 }, }; static { Map> map = new HashMap>(); - map.put(58, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, + map.put(56, Arrays.asList(new TerminalIdentifier[] { WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_TYPE, + })); + map.put(57, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_IMPORT, + })); + map.put(58, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_WORKFLOW, })); map.put(59, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_CALL, })); map.put(60, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_AS, + WdlTerminalIdentifier.TERMINAL_INPUT, })); map.put(61, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_AS, + WdlTerminalIdentifier.TERMINAL_FQN, })); map.put(62, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_WORKFLOW, - WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_FLOAT, + WdlTerminalIdentifier.TERMINAL_LPAREN, + WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_LSQUARE, + WdlTerminalIdentifier.TERMINAL_E, + WdlTerminalIdentifier.TERMINAL_STRING, + WdlTerminalIdentifier.TERMINAL_OBJECT, + WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_NOT, + WdlTerminalIdentifier.TERMINAL_DASH, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_BOOLEAN, + WdlTerminalIdentifier.TERMINAL_PLUS, })); map.put(63, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_CMD_PART, + WdlTerminalIdentifier.TERMINAL_CMD_PARAM_START, })); map.put(64, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_WHILE, - WdlTerminalIdentifier.TERMINAL_CALL, - WdlTerminalIdentifier.TERMINAL_IF, - WdlTerminalIdentifier.TERMINAL_TYPE_E, - WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_SCATTER, + WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_WORKFLOW, })); map.put(65, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RUNTIME, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(66, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_WHILE, + WdlTerminalIdentifier.TERMINAL_COMMA, })); map.put(67, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_TASK, })); map.put(68, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_COMMA, + WdlTerminalIdentifier.TERMINAL_CMD_PARAM_START, })); map.put(69, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_INPUT, + WdlTerminalIdentifier.TERMINAL_AS, })); map.put(70, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CALL, + WdlTerminalIdentifier.TERMINAL_CMD_PART, + WdlTerminalIdentifier.TERMINAL_CMD_PARAM_START, })); map.put(71, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_PARAMETER_META, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(72, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_WORKFLOW, - WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_IF, + WdlTerminalIdentifier.TERMINAL_SCATTER, + WdlTerminalIdentifier.TERMINAL_CALL, + WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_WHILE, + WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(73, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_CMD_ATTR_HINT, })); map.put(74, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_CMD_PART, + WdlTerminalIdentifier.TERMINAL_CMD_PARAM_START, })); map.put(75, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_INPUT, + WdlTerminalIdentifier.TERMINAL_LBRACE, })); map.put(76, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_EQUAL, + WdlTerminalIdentifier.TERMINAL_DOT, })); map.put(77, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CMD_PARAM_START, + WdlTerminalIdentifier.TERMINAL_COMMA, })); map.put(78, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_QMARK, + WdlTerminalIdentifier.TERMINAL_PLUS, })); map.put(79, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_WORKFLOW, })); map.put(80, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_PARAMETER_META, + })); + map.put(81, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_FLOAT, WdlTerminalIdentifier.TERMINAL_NOT, + WdlTerminalIdentifier.TERMINAL_DASH, WdlTerminalIdentifier.TERMINAL_IDENTIFIER, - WdlTerminalIdentifier.TERMINAL_STRING, - WdlTerminalIdentifier.TERMINAL_SQUOTE_STRING, - WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_BOOLEAN, WdlTerminalIdentifier.TERMINAL_LPAREN, - WdlTerminalIdentifier.TERMINAL_E, - WdlTerminalIdentifier.TERMINAL_LSQUARE, - WdlTerminalIdentifier.TERMINAL_DQUOTE_STRING, - WdlTerminalIdentifier.TERMINAL_FLOAT, WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_LSQUARE, + WdlTerminalIdentifier.TERMINAL_E, WdlTerminalIdentifier.TERMINAL_OBJECT, - WdlTerminalIdentifier.TERMINAL_DASH, - WdlTerminalIdentifier.TERMINAL_BOOLEAN, - })); - map.put(81, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_STRING, })); map.put(82, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_PLUS, - WdlTerminalIdentifier.TERMINAL_QMARK, - WdlTerminalIdentifier.TERMINAL_ASTERISK, + WdlTerminalIdentifier.TERMINAL_COMMA, })); map.put(83, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CMD_PART, - WdlTerminalIdentifier.TERMINAL_CMD_PARAM_START, + WdlTerminalIdentifier.TERMINAL_AS, })); map.put(84, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(85, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_RUNTIME, })); map.put(86, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_INPUT, + WdlTerminalIdentifier.TERMINAL_OUTPUT, })); map.put(87, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_IMPORT, + WdlTerminalIdentifier.TERMINAL_WHILE, })); map.put(88, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_OUTPUT, })); map.put(89, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(90, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CMD_ATTR_HINT, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(91, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, + WdlTerminalIdentifier.TERMINAL_IF, + WdlTerminalIdentifier.TERMINAL_CALL, WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_WHILE, + WdlTerminalIdentifier.TERMINAL_SCATTER, + WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(92, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_INPUT, })); map.put(93, Arrays.asList(new TerminalIdentifier[] { WdlTerminalIdentifier.TERMINAL_IMPORT, })); map.put(94, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CMD_PART, - WdlTerminalIdentifier.TERMINAL_CMD_PARAM_START, + WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_IMPORT, + WdlTerminalIdentifier.TERMINAL_WORKFLOW, })); map.put(95, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_IMPORT, })); map.put(96, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_WORKFLOW, + WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(97, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CMD_ATTR_HINT, + WdlTerminalIdentifier.TERMINAL_AS, })); map.put(98, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_PLUS, - WdlTerminalIdentifier.TERMINAL_QMARK, - WdlTerminalIdentifier.TERMINAL_ASTERISK, + WdlTerminalIdentifier.TERMINAL_CMD_ATTR_HINT, })); map.put(99, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_IF, + WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_FLOAT, + WdlTerminalIdentifier.TERMINAL_NOT, + WdlTerminalIdentifier.TERMINAL_DASH, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_BOOLEAN, + WdlTerminalIdentifier.TERMINAL_LPAREN, + WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_LSQUARE, + WdlTerminalIdentifier.TERMINAL_E, + WdlTerminalIdentifier.TERMINAL_STRING, + WdlTerminalIdentifier.TERMINAL_OBJECT, })); map.put(100, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_AS, + WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_PARAMETER_META, + WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, + WdlTerminalIdentifier.TERMINAL_RUNTIME, + WdlTerminalIdentifier.TERMINAL_OUTPUT, })); map.put(101, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CALL, - WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_SCATTER, - WdlTerminalIdentifier.TERMINAL_WHILE, - WdlTerminalIdentifier.TERMINAL_IF, WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(102, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_WORKFLOW, - WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_AS, })); map.put(103, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_OUTPUT, - WdlTerminalIdentifier.TERMINAL_RUNTIME, - WdlTerminalIdentifier.TERMINAL_PARAMETER_META, - WdlTerminalIdentifier.TERMINAL_META, - WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, + WdlTerminalIdentifier.TERMINAL_EQUAL, })); map.put(104, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_AS, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(105, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_LBRACE, })); map.put(106, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_COMMA, + WdlTerminalIdentifier.TERMINAL_LBRACE, })); map.put(107, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CALL, - WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_SCATTER, - WdlTerminalIdentifier.TERMINAL_WHILE, - WdlTerminalIdentifier.TERMINAL_IF, - WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, })); map.put(108, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_PARAMETER_META, WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, - WdlTerminalIdentifier.TERMINAL_OUTPUT, WdlTerminalIdentifier.TERMINAL_RUNTIME, - WdlTerminalIdentifier.TERMINAL_PARAMETER_META, - WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_OUTPUT, })); map.put(109, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_IMPORT, + WdlTerminalIdentifier.TERMINAL_SCATTER, })); map.put(110, Arrays.asList(new TerminalIdentifier[] { WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(111, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, - WdlTerminalIdentifier.TERMINAL_OUTPUT, - WdlTerminalIdentifier.TERMINAL_RUNTIME, - WdlTerminalIdentifier.TERMINAL_PARAMETER_META, - WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_COMMA, })); map.put(112, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_COMMA, + WdlTerminalIdentifier.TERMINAL_CMD_ATTR_HINT, })); map.put(113, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_NOT, - WdlTerminalIdentifier.TERMINAL_E, - WdlTerminalIdentifier.TERMINAL_DQUOTE_STRING, - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, - WdlTerminalIdentifier.TERMINAL_FLOAT, - WdlTerminalIdentifier.TERMINAL_INTEGER, - WdlTerminalIdentifier.TERMINAL_OBJECT, - WdlTerminalIdentifier.TERMINAL_STRING, - WdlTerminalIdentifier.TERMINAL_SQUOTE_STRING, - WdlTerminalIdentifier.TERMINAL_DASH, - WdlTerminalIdentifier.TERMINAL_BOOLEAN, - WdlTerminalIdentifier.TERMINAL_PLUS, - WdlTerminalIdentifier.TERMINAL_LPAREN, - WdlTerminalIdentifier.TERMINAL_LSQUARE, + WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_WORKFLOW, })); map.put(114, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_STRING, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(115, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_SCATTER, + WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(116, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_FQN, })); map.put(117, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CMD_PART, - WdlTerminalIdentifier.TERMINAL_CMD_PARAM_START, + WdlTerminalIdentifier.TERMINAL_QMARK, + WdlTerminalIdentifier.TERMINAL_PLUS, })); map.put(118, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_WORKFLOW, - WdlTerminalIdentifier.TERMINAL_IMPORT, - WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_DOT, })); map.put(119, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_IF, + WdlTerminalIdentifier.TERMINAL_CALL, + WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_WHILE, + WdlTerminalIdentifier.TERMINAL_SCATTER, + WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(120, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, - })); - map.put(121, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, + WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_PARAMETER_META, + WdlTerminalIdentifier.TERMINAL_RUNTIME, + WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, + })); + map.put(121, Arrays.asList(new TerminalIdentifier[] { WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(122, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_COMMA, + WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(123, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_EQUAL, })); map.put(124, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_EQUAL, + WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(125, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CMD_ATTR_HINT, + WdlTerminalIdentifier.TERMINAL_IF, + })); + map.put(126, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_INPUT, + })); + map.put(127, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_META, + })); + map.put(128, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_COMMA, + })); + map.put(129, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_FLOAT, + WdlTerminalIdentifier.TERMINAL_NOT, + WdlTerminalIdentifier.TERMINAL_DASH, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_BOOLEAN, + WdlTerminalIdentifier.TERMINAL_LPAREN, + WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_LSQUARE, + WdlTerminalIdentifier.TERMINAL_OBJECT, + WdlTerminalIdentifier.TERMINAL_E, + WdlTerminalIdentifier.TERMINAL_STRING, + })); + map.put(130, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_COMMA, })); nonterminal_first = Collections.unmodifiableMap(map); } static { Map> map = new HashMap>(); - map.put(58, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RBRACE, - })); - map.put(59, Arrays.asList(new TerminalIdentifier[] { + map.put(56, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_PARAMETER_META, WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, - WdlTerminalIdentifier.TERMINAL_OUTPUT, WdlTerminalIdentifier.TERMINAL_RUNTIME, - WdlTerminalIdentifier.TERMINAL_PARAMETER_META, - WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_OUTPUT, WdlTerminalIdentifier.TERMINAL_INPUT, })); - map.put(60, Arrays.asList(new TerminalIdentifier[] { + map.put(57, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_TASK, WdlTerminalIdentifier.TERMINAL_WORKFLOW, - WdlTerminalIdentifier.TERMINAL_IMPORT, + })); + map.put(58, Arrays.asList(new TerminalIdentifier[] { WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_WORKFLOW, })); - map.put(61, Arrays.asList(new TerminalIdentifier[] { + map.put(59, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_IF, WdlTerminalIdentifier.TERMINAL_CALL, - WdlTerminalIdentifier.TERMINAL_TYPE, WdlTerminalIdentifier.TERMINAL_RBRACE, - WdlTerminalIdentifier.TERMINAL_SCATTER, - WdlTerminalIdentifier.TERMINAL_WHILE, - WdlTerminalIdentifier.TERMINAL_LBRACE, - WdlTerminalIdentifier.TERMINAL_IF, WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_WHILE, + WdlTerminalIdentifier.TERMINAL_SCATTER, + WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_TYPE, + })); + map.put(60, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_RBRACE, + })); + map.put(61, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_COMMA, + WdlTerminalIdentifier.TERMINAL_RBRACE, })); map.put(62, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_WORKFLOW, - WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_RPAREN, + WdlTerminalIdentifier.TERMINAL_RSQUARE, })); map.put(63, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, - WdlTerminalIdentifier.TERMINAL_OUTPUT, - WdlTerminalIdentifier.TERMINAL_RUNTIME, - WdlTerminalIdentifier.TERMINAL_RBRACE, - WdlTerminalIdentifier.TERMINAL_PARAMETER_META, - WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_RAW_CMD_END, })); map.put(64, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_WHILE, - WdlTerminalIdentifier.TERMINAL_CALL, - WdlTerminalIdentifier.TERMINAL_IF, - WdlTerminalIdentifier.TERMINAL_TYPE_E, - WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_RBRACE, - WdlTerminalIdentifier.TERMINAL_SCATTER, })); map.put(65, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, - WdlTerminalIdentifier.TERMINAL_OUTPUT, - WdlTerminalIdentifier.TERMINAL_RUNTIME, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, WdlTerminalIdentifier.TERMINAL_RBRACE, - WdlTerminalIdentifier.TERMINAL_PARAMETER_META, - WdlTerminalIdentifier.TERMINAL_META, })); map.put(66, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CALL, - WdlTerminalIdentifier.TERMINAL_TYPE, + WdlTerminalIdentifier.TERMINAL_INPUT, WdlTerminalIdentifier.TERMINAL_RBRACE, - WdlTerminalIdentifier.TERMINAL_SCATTER, - WdlTerminalIdentifier.TERMINAL_WHILE, - WdlTerminalIdentifier.TERMINAL_IF, - WdlTerminalIdentifier.TERMINAL_TYPE_E, })); map.put(67, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RBRACE, + WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_WORKFLOW, })); map.put(68, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RBRACE, + WdlTerminalIdentifier.TERMINAL_CMD_PART, + WdlTerminalIdentifier.TERMINAL_CMD_PARAM_START, + WdlTerminalIdentifier.TERMINAL_RAW_CMD_END, })); map.put(69, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RBRACE, - })); - map.put(70, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_IF, WdlTerminalIdentifier.TERMINAL_CALL, - WdlTerminalIdentifier.TERMINAL_TYPE, + WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_WHILE, WdlTerminalIdentifier.TERMINAL_RBRACE, WdlTerminalIdentifier.TERMINAL_SCATTER, - WdlTerminalIdentifier.TERMINAL_WHILE, - WdlTerminalIdentifier.TERMINAL_IF, - WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_TYPE, + })); + map.put(70, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_RAW_CMD_END, })); map.put(71, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, - WdlTerminalIdentifier.TERMINAL_OUTPUT, - WdlTerminalIdentifier.TERMINAL_RUNTIME, WdlTerminalIdentifier.TERMINAL_RBRACE, - WdlTerminalIdentifier.TERMINAL_PARAMETER_META, - WdlTerminalIdentifier.TERMINAL_META, })); map.put(72, Arrays.asList(new TerminalIdentifier[] { - })); - map.put(73, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_IF, + WdlTerminalIdentifier.TERMINAL_SCATTER, WdlTerminalIdentifier.TERMINAL_CALL, - WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, - WdlTerminalIdentifier.TERMINAL_OUTPUT, - WdlTerminalIdentifier.TERMINAL_RUNTIME, - WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_INPUT, WdlTerminalIdentifier.TERMINAL_RBRACE, - WdlTerminalIdentifier.TERMINAL_SCATTER, - WdlTerminalIdentifier.TERMINAL_WHILE, - WdlTerminalIdentifier.TERMINAL_IF, WdlTerminalIdentifier.TERMINAL_TYPE_E, - WdlTerminalIdentifier.TERMINAL_PARAMETER_META, - WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_WHILE, + WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_TYPE, })); - map.put(74, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RSQUARE, + map.put(73, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_E, + WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_CMD_ATTR_HINT, + WdlTerminalIdentifier.TERMINAL_FLOAT, + WdlTerminalIdentifier.TERMINAL_NOT, + WdlTerminalIdentifier.TERMINAL_DASH, WdlTerminalIdentifier.TERMINAL_IDENTIFIER, - WdlTerminalIdentifier.TERMINAL_COMMA, + WdlTerminalIdentifier.TERMINAL_BOOLEAN, + WdlTerminalIdentifier.TERMINAL_LPAREN, + WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_LSQUARE, + WdlTerminalIdentifier.TERMINAL_OBJECT, + WdlTerminalIdentifier.TERMINAL_STRING, + WdlTerminalIdentifier.TERMINAL_PLUS, })); - map.put(75, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RBRACE, + map.put(74, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_CMD_PART, + WdlTerminalIdentifier.TERMINAL_CMD_PARAM_START, + WdlTerminalIdentifier.TERMINAL_RAW_CMD_END, })); - map.put(76, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CALL, - WdlTerminalIdentifier.TERMINAL_RUNTIME, - WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_INPUT, + map.put(75, Arrays.asList(new TerminalIdentifier[] { WdlTerminalIdentifier.TERMINAL_IF, + WdlTerminalIdentifier.TERMINAL_CALL, + WdlTerminalIdentifier.TERMINAL_RBRACE, WdlTerminalIdentifier.TERMINAL_TYPE_E, - WdlTerminalIdentifier.TERMINAL_META, - WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, + WdlTerminalIdentifier.TERMINAL_WHILE, + WdlTerminalIdentifier.TERMINAL_SCATTER, WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_TYPE, + })); + map.put(76, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_COMMA, WdlTerminalIdentifier.TERMINAL_RBRACE, - WdlTerminalIdentifier.TERMINAL_SCATTER, - WdlTerminalIdentifier.TERMINAL_WHILE, - WdlTerminalIdentifier.TERMINAL_PARAMETER_META, })); map.put(77, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CMD_PART, - WdlTerminalIdentifier.TERMINAL_CMD_PARAM_START, - WdlTerminalIdentifier.TERMINAL_RAW_CMD_END, + WdlTerminalIdentifier.TERMINAL_RBRACE, })); map.put(78, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, - WdlTerminalIdentifier.TERMINAL_OUTPUT, - WdlTerminalIdentifier.TERMINAL_RUNTIME, - WdlTerminalIdentifier.TERMINAL_RBRACE, - WdlTerminalIdentifier.TERMINAL_PARAMETER_META, - WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(79, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RSQUARE, + WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_WORKFLOW, })); map.put(80, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RSQUARE, - WdlTerminalIdentifier.TERMINAL_RPAREN, + WdlTerminalIdentifier.TERMINAL_RBRACE, + WdlTerminalIdentifier.TERMINAL_RUNTIME, + WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_PARAMETER_META, + WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, + WdlTerminalIdentifier.TERMINAL_OUTPUT, })); map.put(81, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_WORKFLOW, - WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_RBRACE, })); map.put(82, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CMD_PARAM_END, + WdlTerminalIdentifier.TERMINAL_RSQUARE, })); map.put(83, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CMD_PART, - WdlTerminalIdentifier.TERMINAL_CMD_PARAM_START, - WdlTerminalIdentifier.TERMINAL_RAW_CMD_END, + WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_IMPORT, + WdlTerminalIdentifier.TERMINAL_WORKFLOW, })); map.put(84, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RBRACE, + WdlTerminalIdentifier.TERMINAL_QMARK, + WdlTerminalIdentifier.TERMINAL_COMMA, + WdlTerminalIdentifier.TERMINAL_RSQUARE, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_PLUS, })); map.put(85, Arrays.asList(new TerminalIdentifier[] { WdlTerminalIdentifier.TERMINAL_RBRACE, - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_RUNTIME, + WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_PARAMETER_META, + WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, + WdlTerminalIdentifier.TERMINAL_OUTPUT, })); map.put(86, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_INPUT, + WdlTerminalIdentifier.TERMINAL_IF, + WdlTerminalIdentifier.TERMINAL_CALL, WdlTerminalIdentifier.TERMINAL_RBRACE, + WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_WHILE, + WdlTerminalIdentifier.TERMINAL_SCATTER, + WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(87, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_WORKFLOW, - WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_IF, + WdlTerminalIdentifier.TERMINAL_CALL, + WdlTerminalIdentifier.TERMINAL_RBRACE, + WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_WHILE, + WdlTerminalIdentifier.TERMINAL_SCATTER, + WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(88, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, WdlTerminalIdentifier.TERMINAL_RBRACE, - WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_RUNTIME, + WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_PARAMETER_META, + WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, + WdlTerminalIdentifier.TERMINAL_OUTPUT, })); map.put(89, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CALL, - WdlTerminalIdentifier.TERMINAL_TYPE, WdlTerminalIdentifier.TERMINAL_RBRACE, - WdlTerminalIdentifier.TERMINAL_SCATTER, - WdlTerminalIdentifier.TERMINAL_WHILE, - WdlTerminalIdentifier.TERMINAL_IF, - WdlTerminalIdentifier.TERMINAL_TYPE_E, })); map.put(90, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_STRING, + WdlTerminalIdentifier.TERMINAL_COMMA, + WdlTerminalIdentifier.TERMINAL_RBRACE, })); map.put(91, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_RBRACE, })); map.put(92, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, - WdlTerminalIdentifier.TERMINAL_OUTPUT, - WdlTerminalIdentifier.TERMINAL_RUNTIME, + WdlTerminalIdentifier.TERMINAL_INPUT, WdlTerminalIdentifier.TERMINAL_RBRACE, - WdlTerminalIdentifier.TERMINAL_PARAMETER_META, - WdlTerminalIdentifier.TERMINAL_META, })); map.put(93, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_WORKFLOW, WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_IMPORT, + WdlTerminalIdentifier.TERMINAL_WORKFLOW, })); map.put(94, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RAW_CMD_END, })); map.put(95, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_INPUT, - WdlTerminalIdentifier.TERMINAL_RBRACE, + WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_WORKFLOW, })); map.put(96, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_WORKFLOW, - WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_PARAMETER_META, + WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, + WdlTerminalIdentifier.TERMINAL_RUNTIME, + WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_INPUT, })); map.put(97, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_STRING, + WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_IMPORT, + WdlTerminalIdentifier.TERMINAL_WORKFLOW, })); map.put(98, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CMD_PARAM_END, + WdlTerminalIdentifier.TERMINAL_E, + WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_FLOAT, + WdlTerminalIdentifier.TERMINAL_NOT, + WdlTerminalIdentifier.TERMINAL_DASH, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_BOOLEAN, + WdlTerminalIdentifier.TERMINAL_LPAREN, + WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_LSQUARE, + WdlTerminalIdentifier.TERMINAL_OBJECT, + WdlTerminalIdentifier.TERMINAL_STRING, + WdlTerminalIdentifier.TERMINAL_PLUS, })); map.put(99, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CALL, - WdlTerminalIdentifier.TERMINAL_TYPE, + WdlTerminalIdentifier.TERMINAL_COMMA, WdlTerminalIdentifier.TERMINAL_RBRACE, - WdlTerminalIdentifier.TERMINAL_SCATTER, - WdlTerminalIdentifier.TERMINAL_WHILE, - WdlTerminalIdentifier.TERMINAL_IF, - WdlTerminalIdentifier.TERMINAL_TYPE_E, })); map.put(100, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_WORKFLOW, - WdlTerminalIdentifier.TERMINAL_IMPORT, - WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_RBRACE, })); map.put(101, Arrays.asList(new TerminalIdentifier[] { WdlTerminalIdentifier.TERMINAL_RBRACE, })); map.put(102, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_IF, + WdlTerminalIdentifier.TERMINAL_CALL, + WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_WHILE, + WdlTerminalIdentifier.TERMINAL_RBRACE, + WdlTerminalIdentifier.TERMINAL_SCATTER, + WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(103, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, - WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_CALL, WdlTerminalIdentifier.TERMINAL_RUNTIME, WdlTerminalIdentifier.TERMINAL_PARAMETER_META, - WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_SCATTER, + WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, + WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_INPUT, + WdlTerminalIdentifier.TERMINAL_IF, WdlTerminalIdentifier.TERMINAL_RBRACE, + WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_WHILE, + WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(104, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CALL, - WdlTerminalIdentifier.TERMINAL_TYPE, + WdlTerminalIdentifier.TERMINAL_INPUT, WdlTerminalIdentifier.TERMINAL_RBRACE, - WdlTerminalIdentifier.TERMINAL_SCATTER, - WdlTerminalIdentifier.TERMINAL_WHILE, - WdlTerminalIdentifier.TERMINAL_LBRACE, - WdlTerminalIdentifier.TERMINAL_IF, - WdlTerminalIdentifier.TERMINAL_TYPE_E, })); map.put(105, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_INPUT, + WdlTerminalIdentifier.TERMINAL_IF, + WdlTerminalIdentifier.TERMINAL_CALL, WdlTerminalIdentifier.TERMINAL_RBRACE, - WdlTerminalIdentifier.TERMINAL_COMMA, + WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_WHILE, + WdlTerminalIdentifier.TERMINAL_SCATTER, + WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(106, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RSQUARE, + WdlTerminalIdentifier.TERMINAL_RBRACE, + WdlTerminalIdentifier.TERMINAL_RUNTIME, + WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_PARAMETER_META, + WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, + WdlTerminalIdentifier.TERMINAL_OUTPUT, })); map.put(107, Arrays.asList(new TerminalIdentifier[] { WdlTerminalIdentifier.TERMINAL_RBRACE, + WdlTerminalIdentifier.TERMINAL_RUNTIME, + WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_PARAMETER_META, + WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, + WdlTerminalIdentifier.TERMINAL_OUTPUT, })); map.put(108, Arrays.asList(new TerminalIdentifier[] { WdlTerminalIdentifier.TERMINAL_RBRACE, })); map.put(109, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_WORKFLOW, - WdlTerminalIdentifier.TERMINAL_IMPORT, - WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_IF, + WdlTerminalIdentifier.TERMINAL_CALL, + WdlTerminalIdentifier.TERMINAL_RBRACE, + WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_WHILE, + WdlTerminalIdentifier.TERMINAL_SCATTER, + WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(110, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RBRACE, WdlTerminalIdentifier.TERMINAL_COMMA, + WdlTerminalIdentifier.TERMINAL_INPUT, + WdlTerminalIdentifier.TERMINAL_RBRACE, })); map.put(111, Arrays.asList(new TerminalIdentifier[] { WdlTerminalIdentifier.TERMINAL_RBRACE, })); map.put(112, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RSQUARE, - WdlTerminalIdentifier.TERMINAL_RPAREN, - })); - map.put(113, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CALL, - WdlTerminalIdentifier.TERMINAL_INPUT, - WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_PERCENT, - WdlTerminalIdentifier.TERMINAL_RUNTIME, - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, - WdlTerminalIdentifier.TERMINAL_LT, - WdlTerminalIdentifier.TERMINAL_SLASH, - WdlTerminalIdentifier.TERMINAL_GT, - WdlTerminalIdentifier.TERMINAL_STRING, - WdlTerminalIdentifier.TERMINAL_COMMA, - WdlTerminalIdentifier.TERMINAL_NOT_EQUAL, - WdlTerminalIdentifier.TERMINAL_TYPE_E, - WdlTerminalIdentifier.TERMINAL_DOUBLE_PIPE, - WdlTerminalIdentifier.TERMINAL_RSQUARE, - WdlTerminalIdentifier.TERMINAL_LTEQ, - WdlTerminalIdentifier.TERMINAL_IF, WdlTerminalIdentifier.TERMINAL_PLUS, - WdlTerminalIdentifier.TERMINAL_CMD_ATTR_HINT, - WdlTerminalIdentifier.TERMINAL_DOUBLE_EQUAL, - WdlTerminalIdentifier.TERMINAL_ASTERISK, - WdlTerminalIdentifier.TERMINAL_META, - WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, - WdlTerminalIdentifier.TERMINAL_OUTPUT, - WdlTerminalIdentifier.TERMINAL_RBRACE, - WdlTerminalIdentifier.TERMINAL_RPAREN, - WdlTerminalIdentifier.TERMINAL_WHILE, - WdlTerminalIdentifier.TERMINAL_SCATTER, - WdlTerminalIdentifier.TERMINAL_GTEQ, - WdlTerminalIdentifier.TERMINAL_DOUBLE_AMPERSAND, - WdlTerminalIdentifier.TERMINAL_PARAMETER_META, + WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_FLOAT, + WdlTerminalIdentifier.TERMINAL_NOT, WdlTerminalIdentifier.TERMINAL_DASH, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_BOOLEAN, + WdlTerminalIdentifier.TERMINAL_LPAREN, + WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_LSQUARE, + WdlTerminalIdentifier.TERMINAL_OBJECT, + WdlTerminalIdentifier.TERMINAL_STRING, + WdlTerminalIdentifier.TERMINAL_E, + })); + map.put(113, Arrays.asList(new TerminalIdentifier[] { })); map.put(114, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_RBRACE, })); map.put(115, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CALL, - WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_RBRACE, - WdlTerminalIdentifier.TERMINAL_SCATTER, - WdlTerminalIdentifier.TERMINAL_WHILE, - WdlTerminalIdentifier.TERMINAL_IF, WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_RBRACE, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(116, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CALL, - WdlTerminalIdentifier.TERMINAL_TYPE, WdlTerminalIdentifier.TERMINAL_RBRACE, - WdlTerminalIdentifier.TERMINAL_SCATTER, - WdlTerminalIdentifier.TERMINAL_WHILE, - WdlTerminalIdentifier.TERMINAL_IF, - WdlTerminalIdentifier.TERMINAL_TYPE_E, })); map.put(117, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RAW_CMD_END, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(118, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_COMMA, + WdlTerminalIdentifier.TERMINAL_RBRACE, })); map.put(119, Arrays.asList(new TerminalIdentifier[] { WdlTerminalIdentifier.TERMINAL_RBRACE, })); map.put(120, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_PARAMETER_META, WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, - WdlTerminalIdentifier.TERMINAL_OUTPUT, - WdlTerminalIdentifier.TERMINAL_RUNTIME, WdlTerminalIdentifier.TERMINAL_RBRACE, - WdlTerminalIdentifier.TERMINAL_PARAMETER_META, - WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_RUNTIME, + WdlTerminalIdentifier.TERMINAL_OUTPUT, })); map.put(121, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, - WdlTerminalIdentifier.TERMINAL_OUTPUT, - WdlTerminalIdentifier.TERMINAL_RUNTIME, - WdlTerminalIdentifier.TERMINAL_PARAMETER_META, - WdlTerminalIdentifier.TERMINAL_META, - WdlTerminalIdentifier.TERMINAL_INPUT, + WdlTerminalIdentifier.TERMINAL_RBRACE, })); map.put(122, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_INPUT, - WdlTerminalIdentifier.TERMINAL_RBRACE, + WdlTerminalIdentifier.TERMINAL_RSQUARE, })); map.put(123, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RBRACE, - })); - map.put(124, Arrays.asList(new TerminalIdentifier[] { WdlTerminalIdentifier.TERMINAL_CALL, WdlTerminalIdentifier.TERMINAL_RUNTIME, - WdlTerminalIdentifier.TERMINAL_TYPE, + WdlTerminalIdentifier.TERMINAL_PARAMETER_META, + WdlTerminalIdentifier.TERMINAL_SCATTER, + WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, + WdlTerminalIdentifier.TERMINAL_OUTPUT, WdlTerminalIdentifier.TERMINAL_INPUT, WdlTerminalIdentifier.TERMINAL_IF, + WdlTerminalIdentifier.TERMINAL_RBRACE, WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_WHILE, WdlTerminalIdentifier.TERMINAL_META, - WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, - WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_TYPE, + })); + map.put(124, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_IF, + WdlTerminalIdentifier.TERMINAL_CALL, WdlTerminalIdentifier.TERMINAL_RBRACE, - WdlTerminalIdentifier.TERMINAL_SCATTER, + WdlTerminalIdentifier.TERMINAL_TYPE_E, WdlTerminalIdentifier.TERMINAL_WHILE, + WdlTerminalIdentifier.TERMINAL_RUNTIME, + WdlTerminalIdentifier.TERMINAL_META, WdlTerminalIdentifier.TERMINAL_PARAMETER_META, + WdlTerminalIdentifier.TERMINAL_SCATTER, + WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, + WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_INPUT, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(125, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_STRING, + WdlTerminalIdentifier.TERMINAL_IF, + WdlTerminalIdentifier.TERMINAL_CALL, + WdlTerminalIdentifier.TERMINAL_RBRACE, + WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_WHILE, + WdlTerminalIdentifier.TERMINAL_SCATTER, + WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_TYPE, + })); + map.put(126, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_RBRACE, + })); + map.put(127, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_RBRACE, + WdlTerminalIdentifier.TERMINAL_RUNTIME, + WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_PARAMETER_META, + WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, + WdlTerminalIdentifier.TERMINAL_OUTPUT, + })); + map.put(128, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_RBRACE, + })); + map.put(129, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_CALL, + WdlTerminalIdentifier.TERMINAL_FLOAT, + WdlTerminalIdentifier.TERMINAL_PERCENT, + WdlTerminalIdentifier.TERMINAL_GTEQ, + WdlTerminalIdentifier.TERMINAL_SCATTER, + WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, + WdlTerminalIdentifier.TERMINAL_LPAREN, + WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_INPUT, + WdlTerminalIdentifier.TERMINAL_STRING, WdlTerminalIdentifier.TERMINAL_CMD_ATTR_HINT, + WdlTerminalIdentifier.TERMINAL_LTEQ, + WdlTerminalIdentifier.TERMINAL_NOT_EQUAL, + WdlTerminalIdentifier.TERMINAL_GT, + WdlTerminalIdentifier.TERMINAL_DASH, + WdlTerminalIdentifier.TERMINAL_RPAREN, + WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_TYPE, + WdlTerminalIdentifier.TERMINAL_ASTERISK, + WdlTerminalIdentifier.TERMINAL_CMD_PARAM_END, + WdlTerminalIdentifier.TERMINAL_RUNTIME, + WdlTerminalIdentifier.TERMINAL_SLASH, + WdlTerminalIdentifier.TERMINAL_DOUBLE_EQUAL, + WdlTerminalIdentifier.TERMINAL_PARAMETER_META, + WdlTerminalIdentifier.TERMINAL_DOUBLE_AMPERSAND, + WdlTerminalIdentifier.TERMINAL_LT, + WdlTerminalIdentifier.TERMINAL_COMMA, + WdlTerminalIdentifier.TERMINAL_LSQUARE, + WdlTerminalIdentifier.TERMINAL_E, + WdlTerminalIdentifier.TERMINAL_OBJECT, + WdlTerminalIdentifier.TERMINAL_IF, + WdlTerminalIdentifier.TERMINAL_RBRACE, + WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_DOUBLE_PIPE, + WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_WHILE, + WdlTerminalIdentifier.TERMINAL_NOT, + WdlTerminalIdentifier.TERMINAL_RSQUARE, + WdlTerminalIdentifier.TERMINAL_COLON, + WdlTerminalIdentifier.TERMINAL_BOOLEAN, + })); + map.put(130, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_RPAREN, + WdlTerminalIdentifier.TERMINAL_RSQUARE, })); nonterminal_follow = Collections.unmodifiableMap(map); } @@ -1329,21 +1479,21 @@ public enum WdlTerminalIdentifier implements TerminalIdentifier { map.put(3, Arrays.asList(new TerminalIdentifier[] { })); map.put(4, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_WORKFLOW, WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_WORKFLOW, })); map.put(5, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_WORKFLOW, WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_WORKFLOW, })); map.put(6, Arrays.asList(new TerminalIdentifier[] { })); map.put(7, Arrays.asList(new TerminalIdentifier[] { })); map.put(8, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_WORKFLOW, - WdlTerminalIdentifier.TERMINAL_IMPORT, WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_IMPORT, + WdlTerminalIdentifier.TERMINAL_WORKFLOW, })); map.put(9, Arrays.asList(new TerminalIdentifier[] { WdlTerminalIdentifier.TERMINAL_WORKFLOW, @@ -1363,29 +1513,29 @@ public enum WdlTerminalIdentifier implements TerminalIdentifier { WdlTerminalIdentifier.TERMINAL_AS, })); map.put(15, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(16, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(17, Arrays.asList(new TerminalIdentifier[] { })); map.put(18, Arrays.asList(new TerminalIdentifier[] { })); map.put(19, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_OUTPUT, - WdlTerminalIdentifier.TERMINAL_RUNTIME, - WdlTerminalIdentifier.TERMINAL_PARAMETER_META, WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_PARAMETER_META, + WdlTerminalIdentifier.TERMINAL_RUNTIME, + WdlTerminalIdentifier.TERMINAL_OUTPUT, WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, })); map.put(20, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_OUTPUT, - WdlTerminalIdentifier.TERMINAL_RUNTIME, - WdlTerminalIdentifier.TERMINAL_PARAMETER_META, WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_PARAMETER_META, + WdlTerminalIdentifier.TERMINAL_RUNTIME, + WdlTerminalIdentifier.TERMINAL_OUTPUT, WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, })); map.put(21, Arrays.asList(new TerminalIdentifier[] { @@ -1442,97 +1592,111 @@ public enum WdlTerminalIdentifier implements TerminalIdentifier { map.put(39, Arrays.asList(new TerminalIdentifier[] { })); map.put(40, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_STRING, + WdlTerminalIdentifier.TERMINAL_CMD_PARAM_START, })); map.put(41, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_CMD_ATTR_HINT, })); map.put(42, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(43, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(44, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_PLUS, - WdlTerminalIdentifier.TERMINAL_QMARK, - WdlTerminalIdentifier.TERMINAL_ASTERISK, })); map.put(45, Arrays.asList(new TerminalIdentifier[] { })); map.put(46, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CMD_PARAM_START, + WdlTerminalIdentifier.TERMINAL_OUTPUT, })); map.put(47, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CMD_ATTR_HINT, + WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(48, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_QMARK, + WdlTerminalIdentifier.TERMINAL_RUNTIME, })); map.put(49, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_PARAMETER_META, })); map.put(50, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_ASTERISK, + WdlTerminalIdentifier.TERMINAL_META, })); map.put(51, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(52, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(53, Arrays.asList(new TerminalIdentifier[] { })); map.put(54, Arrays.asList(new TerminalIdentifier[] { })); map.put(55, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_LBRACE, })); map.put(56, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(57, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_RUNTIME, + WdlTerminalIdentifier.TERMINAL_QMARK, + WdlTerminalIdentifier.TERMINAL_PLUS, })); map.put(58, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_PARAMETER_META, })); map.put(59, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_EQUAL, })); map.put(60, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(61, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(62, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_EQUAL, })); map.put(63, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_QMARK, })); map.put(64, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_PLUS, })); map.put(65, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_FLOAT, + WdlTerminalIdentifier.TERMINAL_NOT, + WdlTerminalIdentifier.TERMINAL_DASH, WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_BOOLEAN, + WdlTerminalIdentifier.TERMINAL_LPAREN, + WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_LSQUARE, + WdlTerminalIdentifier.TERMINAL_OBJECT, + WdlTerminalIdentifier.TERMINAL_STRING, + WdlTerminalIdentifier.TERMINAL_E, })); map.put(66, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_WHILE, - WdlTerminalIdentifier.TERMINAL_CALL, WdlTerminalIdentifier.TERMINAL_IF, + WdlTerminalIdentifier.TERMINAL_SCATTER, + WdlTerminalIdentifier.TERMINAL_CALL, WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_WHILE, + WdlTerminalIdentifier.TERMINAL_OUTPUT, WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_SCATTER, })); map.put(67, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_WHILE, - WdlTerminalIdentifier.TERMINAL_CALL, WdlTerminalIdentifier.TERMINAL_IF, + WdlTerminalIdentifier.TERMINAL_SCATTER, + WdlTerminalIdentifier.TERMINAL_CALL, WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_WHILE, + WdlTerminalIdentifier.TERMINAL_OUTPUT, WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_SCATTER, })); map.put(68, Arrays.asList(new TerminalIdentifier[] { })); @@ -1545,8 +1709,8 @@ public enum WdlTerminalIdentifier implements TerminalIdentifier { WdlTerminalIdentifier.TERMINAL_CALL, })); map.put(72, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_TYPE, })); map.put(73, Arrays.asList(new TerminalIdentifier[] { WdlTerminalIdentifier.TERMINAL_WHILE, @@ -1558,389 +1722,411 @@ public enum WdlTerminalIdentifier implements TerminalIdentifier { WdlTerminalIdentifier.TERMINAL_SCATTER, })); map.put(76, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_AS, + WdlTerminalIdentifier.TERMINAL_OUTPUT, })); map.put(77, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_AS, })); map.put(78, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_LBRACE, })); map.put(79, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_LBRACE, })); map.put(80, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_CALL, })); map.put(81, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_INPUT, + WdlTerminalIdentifier.TERMINAL_CALL, })); map.put(82, Arrays.asList(new TerminalIdentifier[] { WdlTerminalIdentifier.TERMINAL_INPUT, })); map.put(83, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_INPUT, })); map.put(84, Arrays.asList(new TerminalIdentifier[] { })); map.put(85, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_LBRACE, })); map.put(86, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_LBRACE, })); map.put(87, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_COMMA, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(88, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_COMMA, })); map.put(89, Arrays.asList(new TerminalIdentifier[] { })); map.put(90, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_INPUT, })); map.put(91, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_INPUT, })); map.put(92, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_AS, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(93, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_WHILE, + WdlTerminalIdentifier.TERMINAL_AS, })); map.put(94, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_IF, + WdlTerminalIdentifier.TERMINAL_FQN, })); map.put(95, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_SCATTER, + WdlTerminalIdentifier.TERMINAL_COMMA, })); map.put(96, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_EQUAL, })); map.put(97, Arrays.asList(new TerminalIdentifier[] { })); map.put(98, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_OUTPUT, })); map.put(99, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_EQUAL, + WdlTerminalIdentifier.TERMINAL_DOT, })); map.put(100, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(101, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, - WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_FQN, })); map.put(102, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_COMMA, + WdlTerminalIdentifier.TERMINAL_DOT, })); map.put(103, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_WHILE, })); map.put(104, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_IF, })); map.put(105, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, + WdlTerminalIdentifier.TERMINAL_SCATTER, })); map.put(106, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_TYPE, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(107, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_TYPE_E, + WdlTerminalIdentifier.TERMINAL_TYPE, + })); + map.put(108, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_COMMA, + })); + map.put(109, Arrays.asList(new TerminalIdentifier[] { + })); + map.put(110, Arrays.asList(new TerminalIdentifier[] { + })); + map.put(111, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_TYPE, + })); + map.put(112, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_TYPE, + })); + map.put(113, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_FLOAT, WdlTerminalIdentifier.TERMINAL_NOT, - WdlTerminalIdentifier.TERMINAL_E, - WdlTerminalIdentifier.TERMINAL_DQUOTE_STRING, + WdlTerminalIdentifier.TERMINAL_DASH, WdlTerminalIdentifier.TERMINAL_IDENTIFIER, - WdlTerminalIdentifier.TERMINAL_FLOAT, + WdlTerminalIdentifier.TERMINAL_BOOLEAN, + WdlTerminalIdentifier.TERMINAL_LPAREN, WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_LSQUARE, WdlTerminalIdentifier.TERMINAL_OBJECT, WdlTerminalIdentifier.TERMINAL_STRING, - WdlTerminalIdentifier.TERMINAL_SQUOTE_STRING, + WdlTerminalIdentifier.TERMINAL_E, + })); + map.put(114, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_FLOAT, + WdlTerminalIdentifier.TERMINAL_NOT, WdlTerminalIdentifier.TERMINAL_DASH, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, WdlTerminalIdentifier.TERMINAL_BOOLEAN, - WdlTerminalIdentifier.TERMINAL_PLUS, WdlTerminalIdentifier.TERMINAL_LPAREN, + WdlTerminalIdentifier.TERMINAL_INTEGER, WdlTerminalIdentifier.TERMINAL_LSQUARE, + WdlTerminalIdentifier.TERMINAL_OBJECT, + WdlTerminalIdentifier.TERMINAL_STRING, + WdlTerminalIdentifier.TERMINAL_E, })); - map.put(108, Arrays.asList(new TerminalIdentifier[] { + map.put(115, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_FLOAT, WdlTerminalIdentifier.TERMINAL_NOT, - WdlTerminalIdentifier.TERMINAL_E, - WdlTerminalIdentifier.TERMINAL_DQUOTE_STRING, + WdlTerminalIdentifier.TERMINAL_DASH, WdlTerminalIdentifier.TERMINAL_IDENTIFIER, - WdlTerminalIdentifier.TERMINAL_FLOAT, + WdlTerminalIdentifier.TERMINAL_BOOLEAN, + WdlTerminalIdentifier.TERMINAL_LPAREN, WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_LSQUARE, WdlTerminalIdentifier.TERMINAL_OBJECT, WdlTerminalIdentifier.TERMINAL_STRING, - WdlTerminalIdentifier.TERMINAL_SQUOTE_STRING, - WdlTerminalIdentifier.TERMINAL_DASH, - WdlTerminalIdentifier.TERMINAL_BOOLEAN, - WdlTerminalIdentifier.TERMINAL_PLUS, - WdlTerminalIdentifier.TERMINAL_LPAREN, - WdlTerminalIdentifier.TERMINAL_LSQUARE, - })); - map.put(109, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_NOT, WdlTerminalIdentifier.TERMINAL_E, - WdlTerminalIdentifier.TERMINAL_DQUOTE_STRING, - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + })); + map.put(116, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_LBRACE, WdlTerminalIdentifier.TERMINAL_FLOAT, - WdlTerminalIdentifier.TERMINAL_INTEGER, - WdlTerminalIdentifier.TERMINAL_OBJECT, - WdlTerminalIdentifier.TERMINAL_STRING, - WdlTerminalIdentifier.TERMINAL_SQUOTE_STRING, + WdlTerminalIdentifier.TERMINAL_NOT, WdlTerminalIdentifier.TERMINAL_DASH, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, WdlTerminalIdentifier.TERMINAL_BOOLEAN, - WdlTerminalIdentifier.TERMINAL_PLUS, WdlTerminalIdentifier.TERMINAL_LPAREN, - WdlTerminalIdentifier.TERMINAL_LSQUARE, - })); - map.put(110, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_NOT, - WdlTerminalIdentifier.TERMINAL_E, - WdlTerminalIdentifier.TERMINAL_DQUOTE_STRING, - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, - WdlTerminalIdentifier.TERMINAL_FLOAT, WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_LSQUARE, WdlTerminalIdentifier.TERMINAL_OBJECT, WdlTerminalIdentifier.TERMINAL_STRING, - WdlTerminalIdentifier.TERMINAL_SQUOTE_STRING, - WdlTerminalIdentifier.TERMINAL_DASH, - WdlTerminalIdentifier.TERMINAL_BOOLEAN, - WdlTerminalIdentifier.TERMINAL_PLUS, - WdlTerminalIdentifier.TERMINAL_LPAREN, - WdlTerminalIdentifier.TERMINAL_LSQUARE, - })); - map.put(111, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_NOT, WdlTerminalIdentifier.TERMINAL_E, - WdlTerminalIdentifier.TERMINAL_DQUOTE_STRING, - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + })); + map.put(117, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_LBRACE, WdlTerminalIdentifier.TERMINAL_FLOAT, - WdlTerminalIdentifier.TERMINAL_INTEGER, - WdlTerminalIdentifier.TERMINAL_OBJECT, - WdlTerminalIdentifier.TERMINAL_STRING, - WdlTerminalIdentifier.TERMINAL_SQUOTE_STRING, + WdlTerminalIdentifier.TERMINAL_NOT, WdlTerminalIdentifier.TERMINAL_DASH, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, WdlTerminalIdentifier.TERMINAL_BOOLEAN, - WdlTerminalIdentifier.TERMINAL_PLUS, WdlTerminalIdentifier.TERMINAL_LPAREN, - WdlTerminalIdentifier.TERMINAL_LSQUARE, - })); - map.put(112, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_NOT, - WdlTerminalIdentifier.TERMINAL_E, - WdlTerminalIdentifier.TERMINAL_DQUOTE_STRING, - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, - WdlTerminalIdentifier.TERMINAL_FLOAT, WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_LSQUARE, WdlTerminalIdentifier.TERMINAL_OBJECT, WdlTerminalIdentifier.TERMINAL_STRING, - WdlTerminalIdentifier.TERMINAL_SQUOTE_STRING, - WdlTerminalIdentifier.TERMINAL_DASH, - WdlTerminalIdentifier.TERMINAL_BOOLEAN, - WdlTerminalIdentifier.TERMINAL_PLUS, - WdlTerminalIdentifier.TERMINAL_LPAREN, - WdlTerminalIdentifier.TERMINAL_LSQUARE, - })); - map.put(113, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_NOT, WdlTerminalIdentifier.TERMINAL_E, - WdlTerminalIdentifier.TERMINAL_DQUOTE_STRING, - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + })); + map.put(118, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_LBRACE, WdlTerminalIdentifier.TERMINAL_FLOAT, - WdlTerminalIdentifier.TERMINAL_INTEGER, - WdlTerminalIdentifier.TERMINAL_OBJECT, - WdlTerminalIdentifier.TERMINAL_STRING, - WdlTerminalIdentifier.TERMINAL_SQUOTE_STRING, + WdlTerminalIdentifier.TERMINAL_NOT, WdlTerminalIdentifier.TERMINAL_DASH, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, WdlTerminalIdentifier.TERMINAL_BOOLEAN, - WdlTerminalIdentifier.TERMINAL_PLUS, WdlTerminalIdentifier.TERMINAL_LPAREN, - WdlTerminalIdentifier.TERMINAL_LSQUARE, - })); - map.put(114, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_NOT, - WdlTerminalIdentifier.TERMINAL_E, - WdlTerminalIdentifier.TERMINAL_DQUOTE_STRING, - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, - WdlTerminalIdentifier.TERMINAL_FLOAT, WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_LSQUARE, WdlTerminalIdentifier.TERMINAL_OBJECT, WdlTerminalIdentifier.TERMINAL_STRING, - WdlTerminalIdentifier.TERMINAL_SQUOTE_STRING, - WdlTerminalIdentifier.TERMINAL_DASH, - WdlTerminalIdentifier.TERMINAL_BOOLEAN, - WdlTerminalIdentifier.TERMINAL_PLUS, - WdlTerminalIdentifier.TERMINAL_LPAREN, - WdlTerminalIdentifier.TERMINAL_LSQUARE, - })); - map.put(115, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_NOT, WdlTerminalIdentifier.TERMINAL_E, - WdlTerminalIdentifier.TERMINAL_DQUOTE_STRING, - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + })); + map.put(119, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_LBRACE, WdlTerminalIdentifier.TERMINAL_FLOAT, - WdlTerminalIdentifier.TERMINAL_INTEGER, - WdlTerminalIdentifier.TERMINAL_OBJECT, - WdlTerminalIdentifier.TERMINAL_STRING, - WdlTerminalIdentifier.TERMINAL_SQUOTE_STRING, + WdlTerminalIdentifier.TERMINAL_NOT, WdlTerminalIdentifier.TERMINAL_DASH, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, WdlTerminalIdentifier.TERMINAL_BOOLEAN, - WdlTerminalIdentifier.TERMINAL_PLUS, WdlTerminalIdentifier.TERMINAL_LPAREN, - WdlTerminalIdentifier.TERMINAL_LSQUARE, - })); - map.put(116, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_NOT, - WdlTerminalIdentifier.TERMINAL_E, - WdlTerminalIdentifier.TERMINAL_DQUOTE_STRING, - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, - WdlTerminalIdentifier.TERMINAL_FLOAT, WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_LSQUARE, WdlTerminalIdentifier.TERMINAL_OBJECT, WdlTerminalIdentifier.TERMINAL_STRING, - WdlTerminalIdentifier.TERMINAL_SQUOTE_STRING, - WdlTerminalIdentifier.TERMINAL_DASH, - WdlTerminalIdentifier.TERMINAL_BOOLEAN, - WdlTerminalIdentifier.TERMINAL_PLUS, - WdlTerminalIdentifier.TERMINAL_LPAREN, - WdlTerminalIdentifier.TERMINAL_LSQUARE, - })); - map.put(117, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_NOT, WdlTerminalIdentifier.TERMINAL_E, - WdlTerminalIdentifier.TERMINAL_DQUOTE_STRING, - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + })); + map.put(120, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_LBRACE, WdlTerminalIdentifier.TERMINAL_FLOAT, - WdlTerminalIdentifier.TERMINAL_INTEGER, - WdlTerminalIdentifier.TERMINAL_OBJECT, - WdlTerminalIdentifier.TERMINAL_STRING, - WdlTerminalIdentifier.TERMINAL_SQUOTE_STRING, + WdlTerminalIdentifier.TERMINAL_NOT, WdlTerminalIdentifier.TERMINAL_DASH, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, WdlTerminalIdentifier.TERMINAL_BOOLEAN, - WdlTerminalIdentifier.TERMINAL_PLUS, WdlTerminalIdentifier.TERMINAL_LPAREN, - WdlTerminalIdentifier.TERMINAL_LSQUARE, - })); - map.put(118, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_NOT, - WdlTerminalIdentifier.TERMINAL_E, - WdlTerminalIdentifier.TERMINAL_DQUOTE_STRING, - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, - WdlTerminalIdentifier.TERMINAL_FLOAT, WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_LSQUARE, WdlTerminalIdentifier.TERMINAL_OBJECT, WdlTerminalIdentifier.TERMINAL_STRING, - WdlTerminalIdentifier.TERMINAL_SQUOTE_STRING, + WdlTerminalIdentifier.TERMINAL_E, + })); + map.put(121, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_FLOAT, + WdlTerminalIdentifier.TERMINAL_NOT, WdlTerminalIdentifier.TERMINAL_DASH, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, WdlTerminalIdentifier.TERMINAL_BOOLEAN, - WdlTerminalIdentifier.TERMINAL_PLUS, WdlTerminalIdentifier.TERMINAL_LPAREN, + WdlTerminalIdentifier.TERMINAL_INTEGER, WdlTerminalIdentifier.TERMINAL_LSQUARE, + WdlTerminalIdentifier.TERMINAL_OBJECT, + WdlTerminalIdentifier.TERMINAL_STRING, + WdlTerminalIdentifier.TERMINAL_E, })); - map.put(119, Arrays.asList(new TerminalIdentifier[] { + map.put(122, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_FLOAT, WdlTerminalIdentifier.TERMINAL_NOT, - WdlTerminalIdentifier.TERMINAL_E, - WdlTerminalIdentifier.TERMINAL_DQUOTE_STRING, + WdlTerminalIdentifier.TERMINAL_DASH, WdlTerminalIdentifier.TERMINAL_IDENTIFIER, - WdlTerminalIdentifier.TERMINAL_FLOAT, + WdlTerminalIdentifier.TERMINAL_BOOLEAN, + WdlTerminalIdentifier.TERMINAL_LPAREN, WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_LSQUARE, WdlTerminalIdentifier.TERMINAL_OBJECT, WdlTerminalIdentifier.TERMINAL_STRING, - WdlTerminalIdentifier.TERMINAL_SQUOTE_STRING, + WdlTerminalIdentifier.TERMINAL_E, + })); + map.put(123, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_FLOAT, + WdlTerminalIdentifier.TERMINAL_NOT, WdlTerminalIdentifier.TERMINAL_DASH, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, WdlTerminalIdentifier.TERMINAL_BOOLEAN, - WdlTerminalIdentifier.TERMINAL_PLUS, WdlTerminalIdentifier.TERMINAL_LPAREN, + WdlTerminalIdentifier.TERMINAL_INTEGER, WdlTerminalIdentifier.TERMINAL_LSQUARE, + WdlTerminalIdentifier.TERMINAL_OBJECT, + WdlTerminalIdentifier.TERMINAL_STRING, + WdlTerminalIdentifier.TERMINAL_E, })); - map.put(120, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_NOT, - })); - map.put(121, Arrays.asList(new TerminalIdentifier[] { + map.put(124, Arrays.asList(new TerminalIdentifier[] { WdlTerminalIdentifier.TERMINAL_PLUS, - })); - map.put(122, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_DASH, - })); - map.put(123, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_FLOAT, WdlTerminalIdentifier.TERMINAL_NOT, - WdlTerminalIdentifier.TERMINAL_E, - WdlTerminalIdentifier.TERMINAL_DQUOTE_STRING, + WdlTerminalIdentifier.TERMINAL_DASH, WdlTerminalIdentifier.TERMINAL_IDENTIFIER, - WdlTerminalIdentifier.TERMINAL_FLOAT, + WdlTerminalIdentifier.TERMINAL_BOOLEAN, + WdlTerminalIdentifier.TERMINAL_LPAREN, WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_LSQUARE, WdlTerminalIdentifier.TERMINAL_OBJECT, WdlTerminalIdentifier.TERMINAL_STRING, - WdlTerminalIdentifier.TERMINAL_SQUOTE_STRING, + WdlTerminalIdentifier.TERMINAL_E, + })); + map.put(125, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_FLOAT, + WdlTerminalIdentifier.TERMINAL_NOT, WdlTerminalIdentifier.TERMINAL_DASH, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, WdlTerminalIdentifier.TERMINAL_BOOLEAN, - WdlTerminalIdentifier.TERMINAL_PLUS, WdlTerminalIdentifier.TERMINAL_LPAREN, + WdlTerminalIdentifier.TERMINAL_INTEGER, WdlTerminalIdentifier.TERMINAL_LSQUARE, - })); - map.put(124, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_COMMA, - })); - map.put(125, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_OBJECT, + WdlTerminalIdentifier.TERMINAL_STRING, + WdlTerminalIdentifier.TERMINAL_E, })); map.put(126, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_NOT, })); map.put(127, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_PLUS, })); map.put(128, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_DASH, })); map.put(129, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_FLOAT, + WdlTerminalIdentifier.TERMINAL_NOT, + WdlTerminalIdentifier.TERMINAL_DASH, WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_BOOLEAN, + WdlTerminalIdentifier.TERMINAL_LPAREN, + WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_LSQUARE, + WdlTerminalIdentifier.TERMINAL_OBJECT, + WdlTerminalIdentifier.TERMINAL_STRING, + WdlTerminalIdentifier.TERMINAL_E, })); map.put(130, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_COMMA, })); map.put(131, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_COMMA, })); map.put(132, Arrays.asList(new TerminalIdentifier[] { })); map.put(133, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(134, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_OBJECT, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(135, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_LSQUARE, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(136, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_LPAREN, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(137, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_STRING, + WdlTerminalIdentifier.TERMINAL_COMMA, })); map.put(138, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, })); map.put(139, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_BOOLEAN, })); map.put(140, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_OBJECT, })); map.put(141, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_FLOAT, + WdlTerminalIdentifier.TERMINAL_LSQUARE, })); map.put(142, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_DQUOTE_STRING, - })); - map.put(143, Arrays.asList(new TerminalIdentifier[] { - WdlTerminalIdentifier.TERMINAL_SQUOTE_STRING, - })); - rule_first = Collections.unmodifiableMap(map); - } - static { - Map> map = new HashMap>(); - map.put(58, new ArrayList()); - map.put(59, new ArrayList()); - map.put(60, new ArrayList()); - map.put(61, new ArrayList()); - map.put(62, new ArrayList()); + WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_FLOAT, + WdlTerminalIdentifier.TERMINAL_NOT, + WdlTerminalIdentifier.TERMINAL_DASH, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_BOOLEAN, + WdlTerminalIdentifier.TERMINAL_LPAREN, + WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_LSQUARE, + WdlTerminalIdentifier.TERMINAL_OBJECT, + WdlTerminalIdentifier.TERMINAL_E, + WdlTerminalIdentifier.TERMINAL_STRING, + })); + map.put(143, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_COMMA, + })); + map.put(144, Arrays.asList(new TerminalIdentifier[] { + })); + map.put(145, Arrays.asList(new TerminalIdentifier[] { + })); + map.put(146, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_LBRACE, + })); + map.put(147, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_LPAREN, + })); + map.put(148, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_STRING, + })); + map.put(149, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + })); + map.put(150, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_BOOLEAN, + })); + map.put(151, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_INTEGER, + })); + map.put(152, Arrays.asList(new TerminalIdentifier[] { + WdlTerminalIdentifier.TERMINAL_FLOAT, + })); + rule_first = Collections.unmodifiableMap(map); + } + static { + Map> map = new HashMap>(); + map.put(56, new ArrayList()); + map.put(57, new ArrayList()); + map.put(58, new ArrayList()); + map.put(59, new ArrayList()); + map.put(60, new ArrayList()); + map.put(61, new ArrayList()); + map.put(62, new ArrayList()); map.put(63, new ArrayList()); map.put(64, new ArrayList()); map.put(65, new ArrayList()); @@ -2004,150 +2190,164 @@ public enum WdlTerminalIdentifier implements TerminalIdentifier { map.put(123, new ArrayList()); map.put(124, new ArrayList()); map.put(125, new ArrayList()); - map.get(93).add("$_gen0 = $import $_gen1"); - map.get(87).add("$_gen1 = $import $_gen1"); - map.get(87).add("$_gen1 = :_empty"); - map.get(93).add("$_gen0 = :_empty"); - map.get(102).add("$_gen2 = $workflow_or_task $_gen3"); - map.get(72).add("$_gen3 = $workflow_or_task $_gen3"); - map.get(72).add("$_gen3 = :_empty"); - map.get(102).add("$_gen2 = :_empty"); - map.get(118).add("$document = $_gen0 $_gen2 -> Document( imports=$0, definitions=$1 )"); - map.get(62).add("$workflow_or_task = $workflow"); - map.get(62).add("$workflow_or_task = $task"); - map.get(60).add("$_gen4 = $import_namespace"); - map.get(60).add("$_gen4 = :_empty"); - map.get(109).add("$import = :import :string $_gen4 -> Import( uri=$1, namespace=$2 )"); - map.get(100).add("$import_namespace = :as :identifier -> $1"); - map.get(59).add("$_gen5 = $declaration $_gen6"); - map.get(121).add("$_gen6 = $declaration $_gen6"); - map.get(121).add("$_gen6 = :_empty"); - map.get(59).add("$_gen5 = :_empty"); - map.get(108).add("$_gen7 = $sections $_gen8"); - map.get(111).add("$_gen8 = $sections $_gen8"); - map.get(111).add("$_gen8 = :_empty"); - map.get(108).add("$_gen7 = :_empty"); - map.get(81).add("$task = :task :identifier :lbrace $_gen5 $_gen7 :rbrace -> Task( name=$1, declarations=$3, sections=$4 )"); - map.get(103).add("$sections = $command"); - map.get(103).add("$sections = $outputs"); - map.get(103).add("$sections = $runtime"); - map.get(103).add("$sections = $parameter_meta"); - map.get(103).add("$sections = $meta"); - map.get(117).add("$_gen9 = $command_part $_gen10"); - map.get(94).add("$_gen10 = $command_part $_gen10"); - map.get(94).add("$_gen10 = :_empty"); - map.get(117).add("$_gen9 = :_empty"); - map.get(120).add("$command = :raw_command :raw_cmd_start $_gen9 :raw_cmd_end -> RawCommand( parts=$2 )"); - map.get(83).add("$command_part = :cmd_part"); - map.get(83).add("$command_part = $cmd_param"); - map.get(97).add("$_gen11 = $cmd_param_kv $_gen12"); - map.get(90).add("$_gen12 = $cmd_param_kv $_gen12"); - map.get(90).add("$_gen12 = :_empty"); - map.get(97).add("$_gen11 = :_empty"); - map.get(114).add("$_gen13 = :string"); - map.get(114).add("$_gen13 = :_empty"); - map.get(91).add("$_gen14 = $type_e"); - map.get(91).add("$_gen14 = :_empty"); - map.get(82).add("$_gen15 = $postfix_quantifier"); - map.get(82).add("$_gen15 = :_empty"); - map.get(77).add("$cmd_param = :cmd_param_start $_gen11 $_gen13 $_gen14 :identifier $_gen15 :cmd_param_end -> CommandParameter( name=$4, type=$3, prefix=$2, attributes=$1, postfix=$5 )"); - map.get(125).add("$cmd_param_kv = :cmd_attr_hint :identifier :equal $e -> CommandParameterAttr( key=$1, value=$3 )"); - map.get(98).add("$postfix_quantifier = :qmark"); - map.get(98).add("$postfix_quantifier = :plus"); - map.get(98).add("$postfix_quantifier = :asterisk"); - map.get(58).add("$_gen16 = $output_kv $_gen17"); - map.get(123).add("$_gen17 = $output_kv $_gen17"); - map.get(123).add("$_gen17 = :_empty"); - map.get(58).add("$_gen16 = :_empty"); - map.get(92).add("$outputs = :output :lbrace $_gen16 :rbrace -> Outputs( attributes=$2 )"); - map.get(88).add("$output_kv = $type_e :identifier :equal $e -> Output( type=$0, var=$1, expression=$3 )"); - map.get(65).add("$runtime = :runtime $map -> Runtime( map=$1 )"); - map.get(71).add("$parameter_meta = :parameter_meta $map -> ParameterMeta( map=$1 )"); - map.get(63).add("$meta = :meta $map -> Meta( map=$1 )"); - map.get(67).add("$_gen18 = $kv $_gen19"); - map.get(84).add("$_gen19 = $kv $_gen19"); - map.get(84).add("$_gen19 = :_empty"); - map.get(67).add("$_gen18 = :_empty"); - map.get(78).add("$map = :lbrace $_gen18 :rbrace -> $1"); - map.get(85).add("$kv = :identifier :colon $e -> RuntimeAttribute( key=$0, value=$2 )"); - map.get(107).add("$_gen20 = $wf_body_element $_gen21"); - map.get(101).add("$_gen21 = $wf_body_element $_gen21"); - map.get(101).add("$_gen21 = :_empty"); - map.get(107).add("$_gen20 = :_empty"); - map.get(96).add("$workflow = :workflow :identifier :lbrace $_gen20 :rbrace -> Workflow( name=$1, body=$3 )"); - map.get(64).add("$wf_body_element = $call"); - map.get(64).add("$wf_body_element = $declaration"); - map.get(64).add("$wf_body_element = $while_loop"); - map.get(64).add("$wf_body_element = $if_stmt"); - map.get(64).add("$wf_body_element = $scatter"); - map.get(61).add("$_gen22 = $alias"); - map.get(61).add("$_gen22 = :_empty"); - map.get(89).add("$_gen23 = $call_body"); - map.get(89).add("$_gen23 = :_empty"); - map.get(70).add("$call = :call :ns_identifier $_gen22 $_gen23 -> Call( task=$1, alias=$2, body=$3 )"); - map.get(75).add("$_gen24 = $call_input $_gen25"); - map.get(69).add("$_gen25 = $call_input $_gen25"); - map.get(69).add("$_gen25 = :_empty"); - map.get(75).add("$_gen24 = :_empty"); - map.get(116).add("$call_body = :lbrace $_gen5 $_gen24 :rbrace -> CallBody( declarations=$1, io=$2 )"); - map.get(95).add("$_gen26 = $mapping $_gen27"); - map.get(122).add("$_gen27 = :comma $mapping $_gen27"); - map.get(122).add("$_gen27 = :_empty"); - map.get(95).add("$_gen26 = :_empty"); - map.get(86).add("$call_input = :input :colon $_gen26 -> Inputs( map=$2 )"); - map.get(105).add("$mapping = :identifier :equal $e -> IOMapping( key=$0, value=$2 )"); - map.get(104).add("$alias = :as :identifier -> $1"); - map.get(66).add("$while_loop = :while :lparen $e :rparen :lbrace $_gen20 :rbrace -> WhileLoop( expression=$2, body=$5 )"); - map.get(99).add("$if_stmt = :if :lparen $e :rparen :lbrace $_gen20 :rbrace -> If( expression=$2, body=$5 )"); - map.get(115).add("$scatter = :scatter :lparen :identifier :in $e :rparen :lbrace $_gen20 :rbrace -> Scatter( item=$2, collection=$4, body=$7 )"); - map.get(124).add("$_gen28 = $setter"); - map.get(124).add("$_gen28 = :_empty"); - map.get(73).add("$declaration = $type_e :identifier $_gen28 -> Declaration( type=$0, name=$1, expression=$2 )"); - map.get(76).add("$setter = :equal $e -> $1"); - map.get(110).add("$object_kv = :identifier :colon $e -> ObjectKV( key=$0, value=$2 )"); - map.get(79).add("$_gen29 = $type_e $_gen30"); - map.get(106).add("$_gen30 = :comma $type_e $_gen30"); - map.get(106).add("$_gen30 = :_empty"); - map.get(79).add("$_gen29 = :_empty"); - map.get(74).add("$type_e = :type <=> :lsquare $_gen29 :rsquare -> Type( name=$0, subtype=$2 )"); - map.get(74).add("$type_e = :type"); - map.get(113).add("$e = $e :double_pipe $e -> LogicalOr( lhs=$0, rhs=$2 )"); - map.get(113).add("$e = $e :double_ampersand $e -> LogicalAnd( lhs=$0, rhs=$2 )"); - map.get(113).add("$e = $e :double_equal $e -> Equals( lhs=$0, rhs=$2 )"); - map.get(113).add("$e = $e :not_equal $e -> NotEquals( lhs=$0, rhs=$2 )"); - map.get(113).add("$e = $e :lt $e -> LessThan( lhs=$0, rhs=$2 )"); - map.get(113).add("$e = $e :lteq $e -> LessThanOrEqual( lhs=$0, rhs=$2 )"); - map.get(113).add("$e = $e :gt $e -> GreaterThan( lhs=$0, rhs=$2 )"); - map.get(113).add("$e = $e :gteq $e -> GreaterThanOrEqual( lhs=$0, rhs=$2 )"); - map.get(113).add("$e = $e :plus $e -> Add( lhs=$0, rhs=$2 )"); - map.get(113).add("$e = $e :dash $e -> Subtract( lhs=$0, rhs=$2 )"); - map.get(113).add("$e = $e :asterisk $e -> Multiply( lhs=$0, rhs=$2 )"); - map.get(113).add("$e = $e :slash $e -> Divide( lhs=$0, rhs=$2 )"); - map.get(113).add("$e = $e :percent $e -> Remainder( lhs=$0, rhs=$2 )"); - map.get(113).add("$e = :not $e -> LogicalNot( expression=$1 )"); - map.get(113).add("$e = :plus $e -> UnaryPlus( expression=$1 )"); - map.get(113).add("$e = :dash $e -> UnaryNegation( expression=$1 )"); - map.get(80).add("$_gen31 = $e $_gen32"); - map.get(112).add("$_gen32 = :comma $e $_gen32"); - map.get(112).add("$_gen32 = :_empty"); - map.get(80).add("$_gen31 = :_empty"); - map.get(113).add("$e = :identifier <=> :lparen $_gen31 :rparen -> FunctionCall( name=$0, params=$2 )"); - map.get(113).add("$e = :identifier <=> :lsquare $e :rsquare -> ArrayIndex( lhs=$0, rhs=$2 )"); - map.get(113).add("$e = :identifier <=> :dot :identifier -> MemberAccess( lhs=$0, rhs=$2 )"); - map.get(119).add("$_gen33 = $object_kv $_gen34"); - map.get(68).add("$_gen34 = :comma $object_kv $_gen34"); - map.get(68).add("$_gen34 = :_empty"); - map.get(119).add("$_gen33 = :_empty"); - map.get(113).add("$e = :object :lbrace $_gen33 :rbrace -> ObjectLiteral( map=$2 )"); - map.get(113).add("$e = :lsquare $_gen31 :rsquare -> ArrayLiteral( values=$1 )"); - map.get(113).add("$e = :lparen $e :rparen -> $1"); - map.get(113).add("$e = :string"); - map.get(113).add("$e = :identifier"); - map.get(113).add("$e = :boolean"); - map.get(113).add("$e = :integer"); - map.get(113).add("$e = :float"); - map.get(113).add("$e = :dquote_string"); - map.get(113).add("$e = :squote_string"); + map.put(126, new ArrayList()); + map.put(127, new ArrayList()); + map.put(128, new ArrayList()); + map.put(129, new ArrayList()); + map.put(130, new ArrayList()); + map.get(57).add("$_gen0 = $import $_gen1"); + map.get(95).add("$_gen1 = $import $_gen1"); + map.get(95).add("$_gen1 = :_empty"); + map.get(57).add("$_gen0 = :_empty"); + map.get(113).add("$_gen2 = $workflow_or_task $_gen3"); + map.get(64).add("$_gen3 = $workflow_or_task $_gen3"); + map.get(64).add("$_gen3 = :_empty"); + map.get(113).add("$_gen2 = :_empty"); + map.get(94).add("$document = $_gen0 $_gen2 -> Document( imports=$0, definitions=$1 )"); + map.get(79).add("$workflow_or_task = $workflow"); + map.get(79).add("$workflow_or_task = $task"); + map.get(83).add("$_gen4 = $import_namespace"); + map.get(83).add("$_gen4 = :_empty"); + map.get(93).add("$import = :import :string $_gen4 -> Import( uri=$1, namespace=$2 )"); + map.get(97).add("$import_namespace = :as :identifier -> $1"); + map.get(56).add("$_gen5 = $declaration $_gen6"); + map.get(96).add("$_gen6 = $declaration $_gen6"); + map.get(96).add("$_gen6 = :_empty"); + map.get(56).add("$_gen5 = :_empty"); + map.get(100).add("$_gen7 = $sections $_gen8"); + map.get(108).add("$_gen8 = $sections $_gen8"); + map.get(108).add("$_gen8 = :_empty"); + map.get(100).add("$_gen7 = :_empty"); + map.get(67).add("$task = :task :identifier :lbrace $_gen5 $_gen7 :rbrace -> Task( name=$1, declarations=$3, sections=$4 )"); + map.get(120).add("$sections = $command"); + map.get(120).add("$sections = $outputs"); + map.get(120).add("$sections = $runtime"); + map.get(120).add("$sections = $parameter_meta"); + map.get(120).add("$sections = $meta"); + map.get(63).add("$_gen9 = $command_part $_gen10"); + map.get(70).add("$_gen10 = $command_part $_gen10"); + map.get(70).add("$_gen10 = :_empty"); + map.get(63).add("$_gen9 = :_empty"); + map.get(107).add("$command = :raw_command :raw_cmd_start $_gen9 :raw_cmd_end -> RawCommand( parts=$2 )"); + map.get(74).add("$command_part = :cmd_part"); + map.get(74).add("$command_part = $cmd_param"); + map.get(112).add("$_gen11 = $cmd_param_kv $_gen12"); + map.get(98).add("$_gen12 = $cmd_param_kv $_gen12"); + map.get(98).add("$_gen12 = :_empty"); + map.get(112).add("$_gen11 = :_empty"); + map.get(68).add("$cmd_param = :cmd_param_start $_gen11 $e :cmd_param_end -> CommandParameter( attributes=$1, expr=$2 )"); + map.get(73).add("$cmd_param_kv = :cmd_attr_hint :identifier :equal $e -> CommandParameterAttr( key=$1, value=$3 )"); + map.get(101).add("$_gen13 = $output_kv $_gen14"); + map.get(121).add("$_gen14 = $output_kv $_gen14"); + map.get(121).add("$_gen14 = :_empty"); + map.get(101).add("$_gen13 = :_empty"); + map.get(88).add("$outputs = :output :lbrace $_gen13 :rbrace -> Outputs( attributes=$2 )"); + map.get(115).add("$output_kv = $type_e :identifier :equal $e -> Output( type=$0, var=$1, expression=$3 )"); + map.get(85).add("$runtime = :runtime $map -> Runtime( map=$1 )"); + map.get(80).add("$parameter_meta = :parameter_meta $map -> ParameterMeta( map=$1 )"); + map.get(127).add("$meta = :meta $map -> Meta( map=$1 )"); + map.get(71).add("$_gen15 = $kv $_gen16"); + map.get(89).add("$_gen16 = $kv $_gen16"); + map.get(89).add("$_gen16 = :_empty"); + map.get(71).add("$_gen15 = :_empty"); + map.get(106).add("$map = :lbrace $_gen15 :rbrace -> $1"); + map.get(65).add("$kv = :identifier :colon $e -> RuntimeAttribute( key=$0, value=$2 )"); + map.get(117).add("$_gen17 = $postfix_quantifier"); + map.get(117).add("$_gen17 = :_empty"); + map.get(103).add("$_gen18 = $setter"); + map.get(103).add("$_gen18 = :_empty"); + map.get(124).add("$declaration = $type_e $_gen17 :identifier $_gen18 -> Declaration( type=$0, postfix=$1, name=$2, expression=$3 )"); + map.get(123).add("$setter = :equal $e -> $1"); + map.get(78).add("$postfix_quantifier = :qmark"); + map.get(78).add("$postfix_quantifier = :plus"); + map.get(99).add("$map_kv = $e :colon $e -> MapLiteralKv( key=$0, value=$2 )"); + map.get(119).add("$_gen19 = $wf_body_element $_gen20"); + map.get(91).add("$_gen20 = $wf_body_element $_gen20"); + map.get(91).add("$_gen20 = :_empty"); + map.get(119).add("$_gen19 = :_empty"); + map.get(58).add("$workflow = :workflow :identifier :lbrace $_gen19 :rbrace -> Workflow( name=$1, body=$3 )"); + map.get(72).add("$wf_body_element = $call"); + map.get(72).add("$wf_body_element = $declaration"); + map.get(72).add("$wf_body_element = $while_loop"); + map.get(72).add("$wf_body_element = $if_stmt"); + map.get(72).add("$wf_body_element = $scatter"); + map.get(72).add("$wf_body_element = $wf_outputs"); + map.get(102).add("$_gen21 = $alias"); + map.get(102).add("$_gen21 = :_empty"); + map.get(105).add("$_gen22 = $call_body"); + map.get(105).add("$_gen22 = :_empty"); + map.get(59).add("$call = :call :fqn $_gen21 $_gen22 -> Call( task=$1, alias=$2, body=$3 )"); + map.get(60).add("$_gen23 = $call_input $_gen24"); + map.get(126).add("$_gen24 = $call_input $_gen24"); + map.get(126).add("$_gen24 = :_empty"); + map.get(60).add("$_gen23 = :_empty"); + map.get(75).add("$call_body = :lbrace $_gen5 $_gen23 :rbrace -> CallBody( declarations=$1, io=$2 )"); + map.get(104).add("$_gen25 = $mapping $_gen26"); + map.get(66).add("$_gen26 = :comma $mapping $_gen26"); + map.get(66).add("$_gen26 = :_empty"); + map.get(104).add("$_gen25 = :_empty"); + map.get(92).add("$call_input = :input :colon $_gen25 -> Inputs( map=$2 )"); + map.get(110).add("$mapping = :identifier :equal $e -> IOMapping( key=$0, value=$2 )"); + map.get(69).add("$alias = :as :identifier -> $1"); + map.get(116).add("$_gen27 = $wf_output $_gen28"); + map.get(77).add("$_gen28 = :comma $wf_output $_gen28"); + map.get(77).add("$_gen28 = :_empty"); + map.get(116).add("$_gen27 = :_empty"); + map.get(86).add("$wf_outputs = :output :lbrace $_gen27 :rbrace -> WorkflowOutputs( outputs=$2 )"); + map.get(76).add("$_gen29 = $wf_output_wildcard"); + map.get(76).add("$_gen29 = :_empty"); + map.get(61).add("$wf_output = :fqn $_gen29 -> WorkflowOutput( fqn=$0, wildcard=$1 )"); + map.get(118).add("$wf_output_wildcard = :dot :asterisk -> $1"); + map.get(87).add("$while_loop = :while :lparen $e :rparen :lbrace $_gen19 :rbrace -> WhileLoop( expression=$2, body=$5 )"); + map.get(125).add("$if_stmt = :if :lparen $e :rparen :lbrace $_gen19 :rbrace -> If( expression=$2, body=$5 )"); + map.get(109).add("$scatter = :scatter :lparen :identifier :in $e :rparen :lbrace $_gen19 :rbrace -> Scatter( item=$2, collection=$4, body=$7 )"); + map.get(90).add("$object_kv = :identifier :colon $e -> ObjectKV( key=$0, value=$2 )"); + map.get(122).add("$_gen30 = $type_e $_gen31"); + map.get(82).add("$_gen31 = :comma $type_e $_gen31"); + map.get(82).add("$_gen31 = :_empty"); + map.get(122).add("$_gen30 = :_empty"); + map.get(84).add("$type_e = :type <=> :lsquare $_gen30 :rsquare -> Type( name=$0, subtype=$2 )"); + map.get(84).add("$type_e = :type"); + map.get(129).add("$e = $e :double_pipe $e -> LogicalOr( lhs=$0, rhs=$2 )"); + map.get(129).add("$e = $e :double_ampersand $e -> LogicalAnd( lhs=$0, rhs=$2 )"); + map.get(129).add("$e = $e :double_equal $e -> Equals( lhs=$0, rhs=$2 )"); + map.get(129).add("$e = $e :not_equal $e -> NotEquals( lhs=$0, rhs=$2 )"); + map.get(129).add("$e = $e :lt $e -> LessThan( lhs=$0, rhs=$2 )"); + map.get(129).add("$e = $e :lteq $e -> LessThanOrEqual( lhs=$0, rhs=$2 )"); + map.get(129).add("$e = $e :gt $e -> GreaterThan( lhs=$0, rhs=$2 )"); + map.get(129).add("$e = $e :gteq $e -> GreaterThanOrEqual( lhs=$0, rhs=$2 )"); + map.get(129).add("$e = $e :plus $e -> Add( lhs=$0, rhs=$2 )"); + map.get(129).add("$e = $e :dash $e -> Subtract( lhs=$0, rhs=$2 )"); + map.get(129).add("$e = $e :asterisk $e -> Multiply( lhs=$0, rhs=$2 )"); + map.get(129).add("$e = $e :slash $e -> Divide( lhs=$0, rhs=$2 )"); + map.get(129).add("$e = $e :percent $e -> Remainder( lhs=$0, rhs=$2 )"); + map.get(129).add("$e = :not $e -> LogicalNot( expression=$1 )"); + map.get(129).add("$e = :plus $e -> UnaryPlus( expression=$1 )"); + map.get(129).add("$e = :dash $e -> UnaryNegation( expression=$1 )"); + map.get(62).add("$_gen32 = $e $_gen33"); + map.get(130).add("$_gen33 = :comma $e $_gen33"); + map.get(130).add("$_gen33 = :_empty"); + map.get(62).add("$_gen32 = :_empty"); + map.get(129).add("$e = :identifier <=> :lparen $_gen32 :rparen -> FunctionCall( name=$0, params=$2 )"); + map.get(129).add("$e = :identifier <=> :lsquare $e :rsquare -> ArrayIndex( lhs=$0, rhs=$2 )"); + map.get(129).add("$e = :identifier <=> :dot :identifier -> MemberAccess( lhs=$0, rhs=$2 )"); + map.get(114).add("$_gen34 = $object_kv $_gen35"); + map.get(128).add("$_gen35 = :comma $object_kv $_gen35"); + map.get(128).add("$_gen35 = :_empty"); + map.get(114).add("$_gen34 = :_empty"); + map.get(129).add("$e = :object :lbrace $_gen34 :rbrace -> ObjectLiteral( map=$2 )"); + map.get(129).add("$e = :lsquare $_gen32 :rsquare -> ArrayLiteral( values=$1 )"); + map.get(81).add("$_gen36 = $map_kv $_gen37"); + map.get(111).add("$_gen37 = :comma $map_kv $_gen37"); + map.get(111).add("$_gen37 = :_empty"); + map.get(81).add("$_gen36 = :_empty"); + map.get(129).add("$e = :lbrace $_gen36 :rbrace -> MapLiteral( map=$1 )"); + map.get(129).add("$e = :lparen $e :rparen -> $1"); + map.get(129).add("$e = :string"); + map.get(129).add("$e = :identifier"); + map.get(129).add("$e = :boolean"); + map.get(129).add("$e = :integer"); + map.get(129).add("$e = :float"); nonterminal_rules = Collections.unmodifiableMap(map); } static { @@ -2192,114 +2392,123 @@ public enum WdlTerminalIdentifier implements TerminalIdentifier { map.put(new Integer(37), "$_gen12 = $cmd_param_kv $_gen12"); map.put(new Integer(38), "$_gen12 = :_empty"); map.put(new Integer(39), "$_gen11 = :_empty"); - map.put(new Integer(40), "$_gen13 = :string"); - map.put(new Integer(41), "$_gen13 = :_empty"); - map.put(new Integer(42), "$_gen14 = $type_e"); - map.put(new Integer(43), "$_gen14 = :_empty"); - map.put(new Integer(44), "$_gen15 = $postfix_quantifier"); - map.put(new Integer(45), "$_gen15 = :_empty"); - map.put(new Integer(46), "$cmd_param = :cmd_param_start $_gen11 $_gen13 $_gen14 :identifier $_gen15 :cmd_param_end -> CommandParameter( name=$4, type=$3, prefix=$2, attributes=$1, postfix=$5 )"); - map.put(new Integer(47), "$cmd_param_kv = :cmd_attr_hint :identifier :equal $e -> CommandParameterAttr( key=$1, value=$3 )"); - map.put(new Integer(48), "$postfix_quantifier = :qmark"); - map.put(new Integer(49), "$postfix_quantifier = :plus"); - map.put(new Integer(50), "$postfix_quantifier = :asterisk"); - map.put(new Integer(51), "$_gen16 = $output_kv $_gen17"); - map.put(new Integer(52), "$_gen17 = $output_kv $_gen17"); - map.put(new Integer(53), "$_gen17 = :_empty"); - map.put(new Integer(54), "$_gen16 = :_empty"); - map.put(new Integer(55), "$outputs = :output :lbrace $_gen16 :rbrace -> Outputs( attributes=$2 )"); - map.put(new Integer(56), "$output_kv = $type_e :identifier :equal $e -> Output( type=$0, var=$1, expression=$3 )"); - map.put(new Integer(57), "$runtime = :runtime $map -> Runtime( map=$1 )"); - map.put(new Integer(58), "$parameter_meta = :parameter_meta $map -> ParameterMeta( map=$1 )"); - map.put(new Integer(59), "$meta = :meta $map -> Meta( map=$1 )"); - map.put(new Integer(60), "$_gen18 = $kv $_gen19"); - map.put(new Integer(61), "$_gen19 = $kv $_gen19"); - map.put(new Integer(62), "$_gen19 = :_empty"); - map.put(new Integer(63), "$_gen18 = :_empty"); - map.put(new Integer(64), "$map = :lbrace $_gen18 :rbrace -> $1"); - map.put(new Integer(65), "$kv = :identifier :colon $e -> RuntimeAttribute( key=$0, value=$2 )"); - map.put(new Integer(66), "$_gen20 = $wf_body_element $_gen21"); - map.put(new Integer(67), "$_gen21 = $wf_body_element $_gen21"); - map.put(new Integer(68), "$_gen21 = :_empty"); - map.put(new Integer(69), "$_gen20 = :_empty"); - map.put(new Integer(70), "$workflow = :workflow :identifier :lbrace $_gen20 :rbrace -> Workflow( name=$1, body=$3 )"); + map.put(new Integer(40), "$cmd_param = :cmd_param_start $_gen11 $e :cmd_param_end -> CommandParameter( attributes=$1, expr=$2 )"); + map.put(new Integer(41), "$cmd_param_kv = :cmd_attr_hint :identifier :equal $e -> CommandParameterAttr( key=$1, value=$3 )"); + map.put(new Integer(42), "$_gen13 = $output_kv $_gen14"); + map.put(new Integer(43), "$_gen14 = $output_kv $_gen14"); + map.put(new Integer(44), "$_gen14 = :_empty"); + map.put(new Integer(45), "$_gen13 = :_empty"); + map.put(new Integer(46), "$outputs = :output :lbrace $_gen13 :rbrace -> Outputs( attributes=$2 )"); + map.put(new Integer(47), "$output_kv = $type_e :identifier :equal $e -> Output( type=$0, var=$1, expression=$3 )"); + map.put(new Integer(48), "$runtime = :runtime $map -> Runtime( map=$1 )"); + map.put(new Integer(49), "$parameter_meta = :parameter_meta $map -> ParameterMeta( map=$1 )"); + map.put(new Integer(50), "$meta = :meta $map -> Meta( map=$1 )"); + map.put(new Integer(51), "$_gen15 = $kv $_gen16"); + map.put(new Integer(52), "$_gen16 = $kv $_gen16"); + map.put(new Integer(53), "$_gen16 = :_empty"); + map.put(new Integer(54), "$_gen15 = :_empty"); + map.put(new Integer(55), "$map = :lbrace $_gen15 :rbrace -> $1"); + map.put(new Integer(56), "$kv = :identifier :colon $e -> RuntimeAttribute( key=$0, value=$2 )"); + map.put(new Integer(57), "$_gen17 = $postfix_quantifier"); + map.put(new Integer(58), "$_gen17 = :_empty"); + map.put(new Integer(59), "$_gen18 = $setter"); + map.put(new Integer(60), "$_gen18 = :_empty"); + map.put(new Integer(61), "$declaration = $type_e $_gen17 :identifier $_gen18 -> Declaration( type=$0, postfix=$1, name=$2, expression=$3 )"); + map.put(new Integer(62), "$setter = :equal $e -> $1"); + map.put(new Integer(63), "$postfix_quantifier = :qmark"); + map.put(new Integer(64), "$postfix_quantifier = :plus"); + map.put(new Integer(65), "$map_kv = $e :colon $e -> MapLiteralKv( key=$0, value=$2 )"); + map.put(new Integer(66), "$_gen19 = $wf_body_element $_gen20"); + map.put(new Integer(67), "$_gen20 = $wf_body_element $_gen20"); + map.put(new Integer(68), "$_gen20 = :_empty"); + map.put(new Integer(69), "$_gen19 = :_empty"); + map.put(new Integer(70), "$workflow = :workflow :identifier :lbrace $_gen19 :rbrace -> Workflow( name=$1, body=$3 )"); map.put(new Integer(71), "$wf_body_element = $call"); map.put(new Integer(72), "$wf_body_element = $declaration"); map.put(new Integer(73), "$wf_body_element = $while_loop"); map.put(new Integer(74), "$wf_body_element = $if_stmt"); map.put(new Integer(75), "$wf_body_element = $scatter"); - map.put(new Integer(76), "$_gen22 = $alias"); - map.put(new Integer(77), "$_gen22 = :_empty"); - map.put(new Integer(78), "$_gen23 = $call_body"); - map.put(new Integer(79), "$_gen23 = :_empty"); - map.put(new Integer(80), "$call = :call :ns_identifier $_gen22 $_gen23 -> Call( task=$1, alias=$2, body=$3 )"); - map.put(new Integer(81), "$_gen24 = $call_input $_gen25"); - map.put(new Integer(82), "$_gen25 = $call_input $_gen25"); - map.put(new Integer(83), "$_gen25 = :_empty"); + map.put(new Integer(76), "$wf_body_element = $wf_outputs"); + map.put(new Integer(77), "$_gen21 = $alias"); + map.put(new Integer(78), "$_gen21 = :_empty"); + map.put(new Integer(79), "$_gen22 = $call_body"); + map.put(new Integer(80), "$_gen22 = :_empty"); + map.put(new Integer(81), "$call = :call :fqn $_gen21 $_gen22 -> Call( task=$1, alias=$2, body=$3 )"); + map.put(new Integer(82), "$_gen23 = $call_input $_gen24"); + map.put(new Integer(83), "$_gen24 = $call_input $_gen24"); map.put(new Integer(84), "$_gen24 = :_empty"); - map.put(new Integer(85), "$call_body = :lbrace $_gen5 $_gen24 :rbrace -> CallBody( declarations=$1, io=$2 )"); - map.put(new Integer(86), "$_gen26 = $mapping $_gen27"); - map.put(new Integer(87), "$_gen27 = :comma $mapping $_gen27"); - map.put(new Integer(88), "$_gen27 = :_empty"); + map.put(new Integer(85), "$_gen23 = :_empty"); + map.put(new Integer(86), "$call_body = :lbrace $_gen5 $_gen23 :rbrace -> CallBody( declarations=$1, io=$2 )"); + map.put(new Integer(87), "$_gen25 = $mapping $_gen26"); + map.put(new Integer(88), "$_gen26 = :comma $mapping $_gen26"); map.put(new Integer(89), "$_gen26 = :_empty"); - map.put(new Integer(90), "$call_input = :input :colon $_gen26 -> Inputs( map=$2 )"); - map.put(new Integer(91), "$mapping = :identifier :equal $e -> IOMapping( key=$0, value=$2 )"); - map.put(new Integer(92), "$alias = :as :identifier -> $1"); - map.put(new Integer(93), "$while_loop = :while :lparen $e :rparen :lbrace $_gen20 :rbrace -> WhileLoop( expression=$2, body=$5 )"); - map.put(new Integer(94), "$if_stmt = :if :lparen $e :rparen :lbrace $_gen20 :rbrace -> If( expression=$2, body=$5 )"); - map.put(new Integer(95), "$scatter = :scatter :lparen :identifier :in $e :rparen :lbrace $_gen20 :rbrace -> Scatter( item=$2, collection=$4, body=$7 )"); - map.put(new Integer(96), "$_gen28 = $setter"); - map.put(new Integer(97), "$_gen28 = :_empty"); - map.put(new Integer(98), "$declaration = $type_e :identifier $_gen28 -> Declaration( type=$0, name=$1, expression=$2 )"); - map.put(new Integer(99), "$setter = :equal $e -> $1"); - map.put(new Integer(100), "$object_kv = :identifier :colon $e -> ObjectKV( key=$0, value=$2 )"); - map.put(new Integer(101), "$_gen29 = $type_e $_gen30"); - map.put(new Integer(102), "$_gen30 = :comma $type_e $_gen30"); - map.put(new Integer(103), "$_gen30 = :_empty"); - map.put(new Integer(104), "$_gen29 = :_empty"); - map.put(new Integer(105), "$type_e = :type <=> :lsquare $_gen29 :rsquare -> Type( name=$0, subtype=$2 )"); - map.put(new Integer(106), "$type_e = :type"); - map.put(new Integer(107), "$e = $e :double_pipe $e -> LogicalOr( lhs=$0, rhs=$2 )"); - map.put(new Integer(108), "$e = $e :double_ampersand $e -> LogicalAnd( lhs=$0, rhs=$2 )"); - map.put(new Integer(109), "$e = $e :double_equal $e -> Equals( lhs=$0, rhs=$2 )"); - map.put(new Integer(110), "$e = $e :not_equal $e -> NotEquals( lhs=$0, rhs=$2 )"); - map.put(new Integer(111), "$e = $e :lt $e -> LessThan( lhs=$0, rhs=$2 )"); - map.put(new Integer(112), "$e = $e :lteq $e -> LessThanOrEqual( lhs=$0, rhs=$2 )"); - map.put(new Integer(113), "$e = $e :gt $e -> GreaterThan( lhs=$0, rhs=$2 )"); - map.put(new Integer(114), "$e = $e :gteq $e -> GreaterThanOrEqual( lhs=$0, rhs=$2 )"); - map.put(new Integer(115), "$e = $e :plus $e -> Add( lhs=$0, rhs=$2 )"); - map.put(new Integer(116), "$e = $e :dash $e -> Subtract( lhs=$0, rhs=$2 )"); - map.put(new Integer(117), "$e = $e :asterisk $e -> Multiply( lhs=$0, rhs=$2 )"); - map.put(new Integer(118), "$e = $e :slash $e -> Divide( lhs=$0, rhs=$2 )"); - map.put(new Integer(119), "$e = $e :percent $e -> Remainder( lhs=$0, rhs=$2 )"); - map.put(new Integer(120), "$e = :not $e -> LogicalNot( expression=$1 )"); - map.put(new Integer(121), "$e = :plus $e -> UnaryPlus( expression=$1 )"); - map.put(new Integer(122), "$e = :dash $e -> UnaryNegation( expression=$1 )"); - map.put(new Integer(123), "$_gen31 = $e $_gen32"); - map.put(new Integer(124), "$_gen32 = :comma $e $_gen32"); - map.put(new Integer(125), "$_gen32 = :_empty"); - map.put(new Integer(126), "$_gen31 = :_empty"); - map.put(new Integer(127), "$e = :identifier <=> :lparen $_gen31 :rparen -> FunctionCall( name=$0, params=$2 )"); - map.put(new Integer(128), "$e = :identifier <=> :lsquare $e :rsquare -> ArrayIndex( lhs=$0, rhs=$2 )"); - map.put(new Integer(129), "$e = :identifier <=> :dot :identifier -> MemberAccess( lhs=$0, rhs=$2 )"); - map.put(new Integer(130), "$_gen33 = $object_kv $_gen34"); - map.put(new Integer(131), "$_gen34 = :comma $object_kv $_gen34"); - map.put(new Integer(132), "$_gen34 = :_empty"); - map.put(new Integer(133), "$_gen33 = :_empty"); - map.put(new Integer(134), "$e = :object :lbrace $_gen33 :rbrace -> ObjectLiteral( map=$2 )"); - map.put(new Integer(135), "$e = :lsquare $_gen31 :rsquare -> ArrayLiteral( values=$1 )"); - map.put(new Integer(136), "$e = :lparen $e :rparen -> $1"); - map.put(new Integer(137), "$e = :string"); - map.put(new Integer(138), "$e = :identifier"); - map.put(new Integer(139), "$e = :boolean"); - map.put(new Integer(140), "$e = :integer"); - map.put(new Integer(141), "$e = :float"); - map.put(new Integer(142), "$e = :dquote_string"); - map.put(new Integer(143), "$e = :squote_string"); + map.put(new Integer(90), "$_gen25 = :_empty"); + map.put(new Integer(91), "$call_input = :input :colon $_gen25 -> Inputs( map=$2 )"); + map.put(new Integer(92), "$mapping = :identifier :equal $e -> IOMapping( key=$0, value=$2 )"); + map.put(new Integer(93), "$alias = :as :identifier -> $1"); + map.put(new Integer(94), "$_gen27 = $wf_output $_gen28"); + map.put(new Integer(95), "$_gen28 = :comma $wf_output $_gen28"); + map.put(new Integer(96), "$_gen28 = :_empty"); + map.put(new Integer(97), "$_gen27 = :_empty"); + map.put(new Integer(98), "$wf_outputs = :output :lbrace $_gen27 :rbrace -> WorkflowOutputs( outputs=$2 )"); + map.put(new Integer(99), "$_gen29 = $wf_output_wildcard"); + map.put(new Integer(100), "$_gen29 = :_empty"); + map.put(new Integer(101), "$wf_output = :fqn $_gen29 -> WorkflowOutput( fqn=$0, wildcard=$1 )"); + map.put(new Integer(102), "$wf_output_wildcard = :dot :asterisk -> $1"); + map.put(new Integer(103), "$while_loop = :while :lparen $e :rparen :lbrace $_gen19 :rbrace -> WhileLoop( expression=$2, body=$5 )"); + map.put(new Integer(104), "$if_stmt = :if :lparen $e :rparen :lbrace $_gen19 :rbrace -> If( expression=$2, body=$5 )"); + map.put(new Integer(105), "$scatter = :scatter :lparen :identifier :in $e :rparen :lbrace $_gen19 :rbrace -> Scatter( item=$2, collection=$4, body=$7 )"); + map.put(new Integer(106), "$object_kv = :identifier :colon $e -> ObjectKV( key=$0, value=$2 )"); + map.put(new Integer(107), "$_gen30 = $type_e $_gen31"); + map.put(new Integer(108), "$_gen31 = :comma $type_e $_gen31"); + map.put(new Integer(109), "$_gen31 = :_empty"); + map.put(new Integer(110), "$_gen30 = :_empty"); + map.put(new Integer(111), "$type_e = :type <=> :lsquare $_gen30 :rsquare -> Type( name=$0, subtype=$2 )"); + map.put(new Integer(112), "$type_e = :type"); + map.put(new Integer(113), "$e = $e :double_pipe $e -> LogicalOr( lhs=$0, rhs=$2 )"); + map.put(new Integer(114), "$e = $e :double_ampersand $e -> LogicalAnd( lhs=$0, rhs=$2 )"); + map.put(new Integer(115), "$e = $e :double_equal $e -> Equals( lhs=$0, rhs=$2 )"); + map.put(new Integer(116), "$e = $e :not_equal $e -> NotEquals( lhs=$0, rhs=$2 )"); + map.put(new Integer(117), "$e = $e :lt $e -> LessThan( lhs=$0, rhs=$2 )"); + map.put(new Integer(118), "$e = $e :lteq $e -> LessThanOrEqual( lhs=$0, rhs=$2 )"); + map.put(new Integer(119), "$e = $e :gt $e -> GreaterThan( lhs=$0, rhs=$2 )"); + map.put(new Integer(120), "$e = $e :gteq $e -> GreaterThanOrEqual( lhs=$0, rhs=$2 )"); + map.put(new Integer(121), "$e = $e :plus $e -> Add( lhs=$0, rhs=$2 )"); + map.put(new Integer(122), "$e = $e :dash $e -> Subtract( lhs=$0, rhs=$2 )"); + map.put(new Integer(123), "$e = $e :asterisk $e -> Multiply( lhs=$0, rhs=$2 )"); + map.put(new Integer(124), "$e = $e :slash $e -> Divide( lhs=$0, rhs=$2 )"); + map.put(new Integer(125), "$e = $e :percent $e -> Remainder( lhs=$0, rhs=$2 )"); + map.put(new Integer(126), "$e = :not $e -> LogicalNot( expression=$1 )"); + map.put(new Integer(127), "$e = :plus $e -> UnaryPlus( expression=$1 )"); + map.put(new Integer(128), "$e = :dash $e -> UnaryNegation( expression=$1 )"); + map.put(new Integer(129), "$_gen32 = $e $_gen33"); + map.put(new Integer(130), "$_gen33 = :comma $e $_gen33"); + map.put(new Integer(131), "$_gen33 = :_empty"); + map.put(new Integer(132), "$_gen32 = :_empty"); + map.put(new Integer(133), "$e = :identifier <=> :lparen $_gen32 :rparen -> FunctionCall( name=$0, params=$2 )"); + map.put(new Integer(134), "$e = :identifier <=> :lsquare $e :rsquare -> ArrayIndex( lhs=$0, rhs=$2 )"); + map.put(new Integer(135), "$e = :identifier <=> :dot :identifier -> MemberAccess( lhs=$0, rhs=$2 )"); + map.put(new Integer(136), "$_gen34 = $object_kv $_gen35"); + map.put(new Integer(137), "$_gen35 = :comma $object_kv $_gen35"); + map.put(new Integer(138), "$_gen35 = :_empty"); + map.put(new Integer(139), "$_gen34 = :_empty"); + map.put(new Integer(140), "$e = :object :lbrace $_gen34 :rbrace -> ObjectLiteral( map=$2 )"); + map.put(new Integer(141), "$e = :lsquare $_gen32 :rsquare -> ArrayLiteral( values=$1 )"); + map.put(new Integer(142), "$_gen36 = $map_kv $_gen37"); + map.put(new Integer(143), "$_gen37 = :comma $map_kv $_gen37"); + map.put(new Integer(144), "$_gen37 = :_empty"); + map.put(new Integer(145), "$_gen36 = :_empty"); + map.put(new Integer(146), "$e = :lbrace $_gen36 :rbrace -> MapLiteral( map=$1 )"); + map.put(new Integer(147), "$e = :lparen $e :rparen -> $1"); + map.put(new Integer(148), "$e = :string"); + map.put(new Integer(149), "$e = :identifier"); + map.put(new Integer(150), "$e = :boolean"); + map.put(new Integer(151), "$e = :integer"); + map.put(new Integer(152), "$e = :float"); rules = Collections.unmodifiableMap(map); } public static boolean is_terminal(int id) { - return 0 <= id && id <= 57; + return 0 <= id && id <= 55; } public ParseTree parse(TokenStream tokens) throws SyntaxError { return parse(tokens, new DefaultSyntaxErrorFormatter()); @@ -2339,29 +2548,29 @@ private static Terminal expect(ParserContext ctx, TerminalIdentifier expecting) private static Map prefix_binding_power_e; static { Map map = new HashMap(); - map.put(13, 2000); /* $e = $e :double_pipe $e -> LogicalOr( lhs=$0, rhs=$2 ) */ - map.put(56, 3000); /* $e = $e :double_ampersand $e -> LogicalAnd( lhs=$0, rhs=$2 ) */ - map.put(50, 4000); /* $e = $e :double_equal $e -> Equals( lhs=$0, rhs=$2 ) */ - map.put(10, 4000); /* $e = $e :not_equal $e -> NotEquals( lhs=$0, rhs=$2 ) */ - map.put(6, 5000); /* $e = $e :lt $e -> LessThan( lhs=$0, rhs=$2 ) */ - map.put(44, 5000); /* $e = $e :lteq $e -> LessThanOrEqual( lhs=$0, rhs=$2 ) */ - map.put(8, 5000); /* $e = $e :gt $e -> GreaterThan( lhs=$0, rhs=$2 ) */ - map.put(28, 5000); /* $e = $e :gteq $e -> GreaterThanOrEqual( lhs=$0, rhs=$2 ) */ - map.put(49, 6000); /* $e = $e :plus $e -> Add( lhs=$0, rhs=$2 ) */ - map.put(57, 6000); /* $e = $e :dash $e -> Subtract( lhs=$0, rhs=$2 ) */ - map.put(17, 7000); /* $e = $e :asterisk $e -> Multiply( lhs=$0, rhs=$2 ) */ - map.put(40, 7000); /* $e = $e :slash $e -> Divide( lhs=$0, rhs=$2 ) */ - map.put(37, 7000); /* $e = $e :percent $e -> Remainder( lhs=$0, rhs=$2 ) */ - map.put(14, 9000); /* $e = :identifier <=> :lparen list(nt=$e, sep=:comma, min=0, sep_terminates=False) :rparen -> FunctionCall( name=$0, params=$2 ) */ - map.put(51, 10000); /* $e = :identifier <=> :lsquare $e :rsquare -> ArrayIndex( lhs=$0, rhs=$2 ) */ - map.put(45, 11000); /* $e = :identifier <=> :dot :identifier -> MemberAccess( lhs=$0, rhs=$2 ) */ + map.put(44, 2000); /* $e = $e :double_pipe $e -> LogicalOr( lhs=$0, rhs=$2 ) */ + map.put(30, 3000); /* $e = $e :double_ampersand $e -> LogicalAnd( lhs=$0, rhs=$2 ) */ + map.put(31, 4000); /* $e = $e :double_equal $e -> Equals( lhs=$0, rhs=$2 ) */ + map.put(13, 4000); /* $e = $e :not_equal $e -> NotEquals( lhs=$0, rhs=$2 ) */ + map.put(33, 5000); /* $e = $e :lt $e -> LessThan( lhs=$0, rhs=$2 ) */ + map.put(12, 5000); /* $e = $e :lteq $e -> LessThanOrEqual( lhs=$0, rhs=$2 ) */ + map.put(14, 5000); /* $e = $e :gt $e -> GreaterThan( lhs=$0, rhs=$2 ) */ + map.put(5, 5000); /* $e = $e :gteq $e -> GreaterThanOrEqual( lhs=$0, rhs=$2 ) */ + map.put(20, 6000); /* $e = $e :plus $e -> Add( lhs=$0, rhs=$2 ) */ + map.put(15, 6000); /* $e = $e :dash $e -> Subtract( lhs=$0, rhs=$2 ) */ + map.put(22, 7000); /* $e = $e :asterisk $e -> Multiply( lhs=$0, rhs=$2 ) */ + map.put(27, 7000); /* $e = $e :slash $e -> Divide( lhs=$0, rhs=$2 ) */ + map.put(2, 7000); /* $e = $e :percent $e -> Remainder( lhs=$0, rhs=$2 ) */ + map.put(6, 9000); /* $e = :identifier <=> :lparen list(nt=$e, sep=:comma, min=0, sep_terminates=False) :rparen -> FunctionCall( name=$0, params=$2 ) */ + map.put(35, 10000); /* $e = :identifier <=> :lsquare $e :rsquare -> ArrayIndex( lhs=$0, rhs=$2 ) */ + map.put(21, 11000); /* $e = :identifier <=> :dot :identifier -> MemberAccess( lhs=$0, rhs=$2 ) */ infix_binding_power_e = Collections.unmodifiableMap(map); } static { Map map = new HashMap(); - map.put(33, 8000); /* $e = :not $e -> LogicalNot( expression=$1 ) */ - map.put(49, 8000); /* $e = :plus $e -> UnaryPlus( expression=$1 ) */ - map.put(57, 8000); /* $e = :dash $e -> UnaryNegation( expression=$1 ) */ + map.put(45, 8000); /* $e = :not $e -> LogicalNot( expression=$1 ) */ + map.put(20, 8000); /* $e = :plus $e -> UnaryPlus( expression=$1 ) */ + map.put(15, 8000); /* $e = :dash $e -> UnaryNegation( expression=$1 ) */ prefix_binding_power_e = Collections.unmodifiableMap(map); } static int get_infix_binding_power_e(int terminal_id) { @@ -2398,157 +2607,154 @@ public static ParseTree parse_e_internal(ParserContext ctx, int rbp) throws Synt return left; } private static ParseTree nud_e(ParserContext ctx) throws SyntaxError { - ParseTree tree = new ParseTree( new NonTerminal(113, "e") ); + ParseTree tree = new ParseTree( new NonTerminal(129, "e") ); Terminal current = ctx.tokens.current(); ctx.nonterminal = "e"; if (current == null) { return tree; } - else if (rule_first.get(120).contains(terminal_map.get(current.getId()))) { - /* (120) $e = :not $e -> LogicalNot( expression=$1 ) */ - ctx.rule = rules.get(120); + else if (rule_first.get(126).contains(terminal_map.get(current.getId()))) { + /* (126) $e = :not $e -> LogicalNot( expression=$1 ) */ + ctx.rule = rules.get(126); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("expression", 1); tree.setAstTransformation(new AstTransformNodeCreator("LogicalNot", parameters)); tree.setNudMorphemeCount(2); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_NOT)); - tree.add(parse_e_internal(ctx, get_prefix_binding_power_e(33))); + tree.add(parse_e_internal(ctx, get_prefix_binding_power_e(45))); tree.setPrefix(true); } - else if (rule_first.get(121).contains(terminal_map.get(current.getId()))) { - /* (121) $e = :plus $e -> UnaryPlus( expression=$1 ) */ - ctx.rule = rules.get(121); + else if (rule_first.get(127).contains(terminal_map.get(current.getId()))) { + /* (127) $e = :plus $e -> UnaryPlus( expression=$1 ) */ + ctx.rule = rules.get(127); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("expression", 1); tree.setAstTransformation(new AstTransformNodeCreator("UnaryPlus", parameters)); tree.setNudMorphemeCount(2); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_PLUS)); - tree.add(parse_e_internal(ctx, get_prefix_binding_power_e(49))); + tree.add(parse_e_internal(ctx, get_prefix_binding_power_e(20))); tree.setPrefix(true); } - else if (rule_first.get(122).contains(terminal_map.get(current.getId()))) { - /* (122) $e = :dash $e -> UnaryNegation( expression=$1 ) */ - ctx.rule = rules.get(122); + else if (rule_first.get(128).contains(terminal_map.get(current.getId()))) { + /* (128) $e = :dash $e -> UnaryNegation( expression=$1 ) */ + ctx.rule = rules.get(128); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("expression", 1); tree.setAstTransformation(new AstTransformNodeCreator("UnaryNegation", parameters)); tree.setNudMorphemeCount(2); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_DASH)); - tree.add(parse_e_internal(ctx, get_prefix_binding_power_e(57))); + tree.add(parse_e_internal(ctx, get_prefix_binding_power_e(15))); tree.setPrefix(true); } - else if (rule_first.get(127).contains(terminal_map.get(current.getId()))) { - /* (127) $e = :identifier <=> :lparen $_gen31 :rparen -> FunctionCall( name=$0, params=$2 ) */ - ctx.rule = rules.get(127); + else if (rule_first.get(133).contains(terminal_map.get(current.getId()))) { + /* (133) $e = :identifier <=> :lparen $_gen32 :rparen -> FunctionCall( name=$0, params=$2 ) */ + ctx.rule = rules.get(133); tree.setAstTransformation(new AstTransformSubstitution(0)); tree.setNudMorphemeCount(1); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER)); } - else if (rule_first.get(128).contains(terminal_map.get(current.getId()))) { - /* (128) $e = :identifier <=> :lsquare $e :rsquare -> ArrayIndex( lhs=$0, rhs=$2 ) */ - ctx.rule = rules.get(128); + else if (rule_first.get(134).contains(terminal_map.get(current.getId()))) { + /* (134) $e = :identifier <=> :lsquare $e :rsquare -> ArrayIndex( lhs=$0, rhs=$2 ) */ + ctx.rule = rules.get(134); tree.setAstTransformation(new AstTransformSubstitution(0)); tree.setNudMorphemeCount(1); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER)); } - else if (rule_first.get(129).contains(terminal_map.get(current.getId()))) { - /* (129) $e = :identifier <=> :dot :identifier -> MemberAccess( lhs=$0, rhs=$2 ) */ - ctx.rule = rules.get(129); + else if (rule_first.get(135).contains(terminal_map.get(current.getId()))) { + /* (135) $e = :identifier <=> :dot :identifier -> MemberAccess( lhs=$0, rhs=$2 ) */ + ctx.rule = rules.get(135); tree.setAstTransformation(new AstTransformSubstitution(0)); tree.setNudMorphemeCount(1); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER)); } - else if (rule_first.get(134).contains(terminal_map.get(current.getId()))) { - /* (134) $e = :object :lbrace $_gen33 :rbrace -> ObjectLiteral( map=$2 ) */ - ctx.rule = rules.get(134); + else if (rule_first.get(140).contains(terminal_map.get(current.getId()))) { + /* (140) $e = :object :lbrace $_gen34 :rbrace -> ObjectLiteral( map=$2 ) */ + ctx.rule = rules.get(140); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("map", 2); tree.setAstTransformation(new AstTransformNodeCreator("ObjectLiteral", parameters)); tree.setNudMorphemeCount(4); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_OBJECT)); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_LBRACE)); - tree.add(parse__gen33(ctx)); + tree.add(parse__gen34(ctx)); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_RBRACE)); } - else if (rule_first.get(135).contains(terminal_map.get(current.getId()))) { - /* (135) $e = :lsquare $_gen31 :rsquare -> ArrayLiteral( values=$1 ) */ - ctx.rule = rules.get(135); + else if (rule_first.get(141).contains(terminal_map.get(current.getId()))) { + /* (141) $e = :lsquare $_gen32 :rsquare -> ArrayLiteral( values=$1 ) */ + ctx.rule = rules.get(141); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("values", 1); tree.setAstTransformation(new AstTransformNodeCreator("ArrayLiteral", parameters)); tree.setNudMorphemeCount(3); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_LSQUARE)); - tree.add(parse__gen31(ctx)); + tree.add(parse__gen32(ctx)); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_RSQUARE)); } - else if (rule_first.get(136).contains(terminal_map.get(current.getId()))) { - /* (136) $e = :lparen $e :rparen -> $1 */ - ctx.rule = rules.get(136); + else if (rule_first.get(146).contains(terminal_map.get(current.getId()))) { + /* (146) $e = :lbrace $_gen36 :rbrace -> MapLiteral( map=$1 ) */ + ctx.rule = rules.get(146); + LinkedHashMap parameters = new LinkedHashMap(); + parameters.put("map", 1); + tree.setAstTransformation(new AstTransformNodeCreator("MapLiteral", parameters)); + tree.setNudMorphemeCount(3); + tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_LBRACE)); + tree.add(parse__gen36(ctx)); + tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_RBRACE)); + } + else if (rule_first.get(147).contains(terminal_map.get(current.getId()))) { + /* (147) $e = :lparen $e :rparen -> $1 */ + ctx.rule = rules.get(147); tree.setAstTransformation(new AstTransformSubstitution(1)); tree.setNudMorphemeCount(3); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_LPAREN)); tree.add(parse_e(ctx)); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_RPAREN)); } - else if (rule_first.get(137).contains(terminal_map.get(current.getId()))) { - /* (137) $e = :string */ - ctx.rule = rules.get(137); + else if (rule_first.get(148).contains(terminal_map.get(current.getId()))) { + /* (148) $e = :string */ + ctx.rule = rules.get(148); tree.setAstTransformation(new AstTransformSubstitution(0)); tree.setNudMorphemeCount(1); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_STRING)); } - else if (rule_first.get(138).contains(terminal_map.get(current.getId()))) { - /* (138) $e = :identifier */ - ctx.rule = rules.get(138); + else if (rule_first.get(149).contains(terminal_map.get(current.getId()))) { + /* (149) $e = :identifier */ + ctx.rule = rules.get(149); tree.setAstTransformation(new AstTransformSubstitution(0)); tree.setNudMorphemeCount(1); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER)); } - else if (rule_first.get(139).contains(terminal_map.get(current.getId()))) { - /* (139) $e = :boolean */ - ctx.rule = rules.get(139); + else if (rule_first.get(150).contains(terminal_map.get(current.getId()))) { + /* (150) $e = :boolean */ + ctx.rule = rules.get(150); tree.setAstTransformation(new AstTransformSubstitution(0)); tree.setNudMorphemeCount(1); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_BOOLEAN)); } - else if (rule_first.get(140).contains(terminal_map.get(current.getId()))) { - /* (140) $e = :integer */ - ctx.rule = rules.get(140); + else if (rule_first.get(151).contains(terminal_map.get(current.getId()))) { + /* (151) $e = :integer */ + ctx.rule = rules.get(151); tree.setAstTransformation(new AstTransformSubstitution(0)); tree.setNudMorphemeCount(1); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_INTEGER)); } - else if (rule_first.get(141).contains(terminal_map.get(current.getId()))) { - /* (141) $e = :float */ - ctx.rule = rules.get(141); + else if (rule_first.get(152).contains(terminal_map.get(current.getId()))) { + /* (152) $e = :float */ + ctx.rule = rules.get(152); tree.setAstTransformation(new AstTransformSubstitution(0)); tree.setNudMorphemeCount(1); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_FLOAT)); } - else if (rule_first.get(142).contains(terminal_map.get(current.getId()))) { - /* (142) $e = :dquote_string */ - ctx.rule = rules.get(142); - tree.setAstTransformation(new AstTransformSubstitution(0)); - tree.setNudMorphemeCount(1); - tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_DQUOTE_STRING)); - } - else if (rule_first.get(143).contains(terminal_map.get(current.getId()))) { - /* (143) $e = :squote_string */ - ctx.rule = rules.get(143); - tree.setAstTransformation(new AstTransformSubstitution(0)); - tree.setNudMorphemeCount(1); - tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_SQUOTE_STRING)); - } return tree; } private static ParseTree led_e(ParseTree left, ParserContext ctx) throws SyntaxError { - ParseTree tree = new ParseTree( new NonTerminal(113, "e") ); + ParseTree tree = new ParseTree( new NonTerminal(129, "e") ); Terminal current = ctx.tokens.current(); ctx.nonterminal = "e"; int modifier; - if (current.getId() == 13) { + if (current.getId() == 44) { /* $e = $e :double_pipe $e -> LogicalOr( lhs=$0, rhs=$2 ) */ - ctx.rule = rules.get(107); + ctx.rule = rules.get(113); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("lhs", 0); parameters.put("rhs", 2); @@ -2558,12 +2764,12 @@ private static ParseTree led_e(ParseTree left, ParserContext ctx) throws SyntaxE tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_DOUBLE_PIPE)); modifier = 0; tree.setInfix(true); - tree.add(parse_e_internal(ctx, get_infix_binding_power_e(13) - modifier)); + tree.add(parse_e_internal(ctx, get_infix_binding_power_e(44) - modifier)); return tree; } - if (current.getId() == 56) { + if (current.getId() == 30) { /* $e = $e :double_ampersand $e -> LogicalAnd( lhs=$0, rhs=$2 ) */ - ctx.rule = rules.get(108); + ctx.rule = rules.get(114); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("lhs", 0); parameters.put("rhs", 2); @@ -2573,12 +2779,12 @@ private static ParseTree led_e(ParseTree left, ParserContext ctx) throws SyntaxE tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_DOUBLE_AMPERSAND)); modifier = 0; tree.setInfix(true); - tree.add(parse_e_internal(ctx, get_infix_binding_power_e(56) - modifier)); + tree.add(parse_e_internal(ctx, get_infix_binding_power_e(30) - modifier)); return tree; } - if (current.getId() == 50) { + if (current.getId() == 31) { /* $e = $e :double_equal $e -> Equals( lhs=$0, rhs=$2 ) */ - ctx.rule = rules.get(109); + ctx.rule = rules.get(115); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("lhs", 0); parameters.put("rhs", 2); @@ -2588,12 +2794,12 @@ private static ParseTree led_e(ParseTree left, ParserContext ctx) throws SyntaxE tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_DOUBLE_EQUAL)); modifier = 0; tree.setInfix(true); - tree.add(parse_e_internal(ctx, get_infix_binding_power_e(50) - modifier)); + tree.add(parse_e_internal(ctx, get_infix_binding_power_e(31) - modifier)); return tree; } - if (current.getId() == 10) { + if (current.getId() == 13) { /* $e = $e :not_equal $e -> NotEquals( lhs=$0, rhs=$2 ) */ - ctx.rule = rules.get(110); + ctx.rule = rules.get(116); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("lhs", 0); parameters.put("rhs", 2); @@ -2603,12 +2809,12 @@ private static ParseTree led_e(ParseTree left, ParserContext ctx) throws SyntaxE tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_NOT_EQUAL)); modifier = 0; tree.setInfix(true); - tree.add(parse_e_internal(ctx, get_infix_binding_power_e(10) - modifier)); + tree.add(parse_e_internal(ctx, get_infix_binding_power_e(13) - modifier)); return tree; } - if (current.getId() == 6) { + if (current.getId() == 33) { /* $e = $e :lt $e -> LessThan( lhs=$0, rhs=$2 ) */ - ctx.rule = rules.get(111); + ctx.rule = rules.get(117); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("lhs", 0); parameters.put("rhs", 2); @@ -2618,12 +2824,12 @@ private static ParseTree led_e(ParseTree left, ParserContext ctx) throws SyntaxE tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_LT)); modifier = 0; tree.setInfix(true); - tree.add(parse_e_internal(ctx, get_infix_binding_power_e(6) - modifier)); + tree.add(parse_e_internal(ctx, get_infix_binding_power_e(33) - modifier)); return tree; } - if (current.getId() == 44) { + if (current.getId() == 12) { /* $e = $e :lteq $e -> LessThanOrEqual( lhs=$0, rhs=$2 ) */ - ctx.rule = rules.get(112); + ctx.rule = rules.get(118); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("lhs", 0); parameters.put("rhs", 2); @@ -2633,12 +2839,12 @@ private static ParseTree led_e(ParseTree left, ParserContext ctx) throws SyntaxE tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_LTEQ)); modifier = 0; tree.setInfix(true); - tree.add(parse_e_internal(ctx, get_infix_binding_power_e(44) - modifier)); + tree.add(parse_e_internal(ctx, get_infix_binding_power_e(12) - modifier)); return tree; } - if (current.getId() == 8) { + if (current.getId() == 14) { /* $e = $e :gt $e -> GreaterThan( lhs=$0, rhs=$2 ) */ - ctx.rule = rules.get(113); + ctx.rule = rules.get(119); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("lhs", 0); parameters.put("rhs", 2); @@ -2648,12 +2854,12 @@ private static ParseTree led_e(ParseTree left, ParserContext ctx) throws SyntaxE tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_GT)); modifier = 0; tree.setInfix(true); - tree.add(parse_e_internal(ctx, get_infix_binding_power_e(8) - modifier)); + tree.add(parse_e_internal(ctx, get_infix_binding_power_e(14) - modifier)); return tree; } - if (current.getId() == 28) { + if (current.getId() == 5) { /* $e = $e :gteq $e -> GreaterThanOrEqual( lhs=$0, rhs=$2 ) */ - ctx.rule = rules.get(114); + ctx.rule = rules.get(120); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("lhs", 0); parameters.put("rhs", 2); @@ -2663,12 +2869,12 @@ private static ParseTree led_e(ParseTree left, ParserContext ctx) throws SyntaxE tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_GTEQ)); modifier = 0; tree.setInfix(true); - tree.add(parse_e_internal(ctx, get_infix_binding_power_e(28) - modifier)); + tree.add(parse_e_internal(ctx, get_infix_binding_power_e(5) - modifier)); return tree; } - if (current.getId() == 49) { + if (current.getId() == 20) { /* $e = $e :plus $e -> Add( lhs=$0, rhs=$2 ) */ - ctx.rule = rules.get(115); + ctx.rule = rules.get(121); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("lhs", 0); parameters.put("rhs", 2); @@ -2678,12 +2884,12 @@ private static ParseTree led_e(ParseTree left, ParserContext ctx) throws SyntaxE tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_PLUS)); modifier = 0; tree.setInfix(true); - tree.add(parse_e_internal(ctx, get_infix_binding_power_e(49) - modifier)); + tree.add(parse_e_internal(ctx, get_infix_binding_power_e(20) - modifier)); return tree; } - if (current.getId() == 57) { + if (current.getId() == 15) { /* $e = $e :dash $e -> Subtract( lhs=$0, rhs=$2 ) */ - ctx.rule = rules.get(116); + ctx.rule = rules.get(122); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("lhs", 0); parameters.put("rhs", 2); @@ -2693,12 +2899,12 @@ private static ParseTree led_e(ParseTree left, ParserContext ctx) throws SyntaxE tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_DASH)); modifier = 0; tree.setInfix(true); - tree.add(parse_e_internal(ctx, get_infix_binding_power_e(57) - modifier)); + tree.add(parse_e_internal(ctx, get_infix_binding_power_e(15) - modifier)); return tree; } - if (current.getId() == 17) { + if (current.getId() == 22) { /* $e = $e :asterisk $e -> Multiply( lhs=$0, rhs=$2 ) */ - ctx.rule = rules.get(117); + ctx.rule = rules.get(123); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("lhs", 0); parameters.put("rhs", 2); @@ -2708,12 +2914,12 @@ private static ParseTree led_e(ParseTree left, ParserContext ctx) throws SyntaxE tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_ASTERISK)); modifier = 0; tree.setInfix(true); - tree.add(parse_e_internal(ctx, get_infix_binding_power_e(17) - modifier)); + tree.add(parse_e_internal(ctx, get_infix_binding_power_e(22) - modifier)); return tree; } - if (current.getId() == 40) { + if (current.getId() == 27) { /* $e = $e :slash $e -> Divide( lhs=$0, rhs=$2 ) */ - ctx.rule = rules.get(118); + ctx.rule = rules.get(124); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("lhs", 0); parameters.put("rhs", 2); @@ -2723,12 +2929,12 @@ private static ParseTree led_e(ParseTree left, ParserContext ctx) throws SyntaxE tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_SLASH)); modifier = 0; tree.setInfix(true); - tree.add(parse_e_internal(ctx, get_infix_binding_power_e(40) - modifier)); + tree.add(parse_e_internal(ctx, get_infix_binding_power_e(27) - modifier)); return tree; } - if (current.getId() == 37) { + if (current.getId() == 2) { /* $e = $e :percent $e -> Remainder( lhs=$0, rhs=$2 ) */ - ctx.rule = rules.get(119); + ctx.rule = rules.get(125); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("lhs", 0); parameters.put("rhs", 2); @@ -2738,25 +2944,25 @@ private static ParseTree led_e(ParseTree left, ParserContext ctx) throws SyntaxE tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_PERCENT)); modifier = 0; tree.setInfix(true); - tree.add(parse_e_internal(ctx, get_infix_binding_power_e(37) - modifier)); + tree.add(parse_e_internal(ctx, get_infix_binding_power_e(2) - modifier)); return tree; } - if (current.getId() == 14) { - /* $e = :identifier <=> :lparen $_gen31 :rparen -> FunctionCall( name=$0, params=$2 ) */ - ctx.rule = rules.get(127); + if (current.getId() == 6) { + /* $e = :identifier <=> :lparen $_gen32 :rparen -> FunctionCall( name=$0, params=$2 ) */ + ctx.rule = rules.get(133); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("name", 0); parameters.put("params", 2); tree.setAstTransformation(new AstTransformNodeCreator("FunctionCall", parameters)); tree.add(left); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_LPAREN)); - tree.add(parse__gen31(ctx)); + tree.add(parse__gen32(ctx)); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_RPAREN)); return tree; } - if (current.getId() == 51) { + if (current.getId() == 35) { /* $e = :identifier <=> :lsquare $e :rsquare -> ArrayIndex( lhs=$0, rhs=$2 ) */ - ctx.rule = rules.get(128); + ctx.rule = rules.get(134); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("lhs", 0); parameters.put("rhs", 2); @@ -2764,13 +2970,13 @@ private static ParseTree led_e(ParseTree left, ParserContext ctx) throws SyntaxE tree.add(left); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_LSQUARE)); modifier = 0; - tree.add(parse_e_internal(ctx, get_infix_binding_power_e(51) - modifier)); + tree.add(parse_e_internal(ctx, get_infix_binding_power_e(35) - modifier)); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_RSQUARE)); return tree; } - if (current.getId() == 45) { + if (current.getId() == 21) { /* $e = :identifier <=> :dot :identifier -> MemberAccess( lhs=$0, rhs=$2 ) */ - ctx.rule = rules.get(129); + ctx.rule = rules.get(135); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("lhs", 0); parameters.put("rhs", 2); @@ -2786,7 +2992,7 @@ private static ParseTree led_e(ParseTree left, ParserContext ctx) throws SyntaxE private static Map prefix_binding_power_type_e; static { Map map = new HashMap(); - map.put(51, 1000); /* $type_e = :type <=> :lsquare list(nt=$type_e, sep=:comma, min=0, sep_terminates=False) :rsquare -> Type( name=$0, subtype=$2 ) */ + map.put(35, 1000); /* $type_e = :type <=> :lsquare list(nt=$type_e, sep=:comma, min=0, sep_terminates=False) :rsquare -> Type( name=$0, subtype=$2 ) */ infix_binding_power_type_e = Collections.unmodifiableMap(map); } static { @@ -2827,22 +3033,22 @@ public static ParseTree parse_type_e_internal(ParserContext ctx, int rbp) throws return left; } private static ParseTree nud_type_e(ParserContext ctx) throws SyntaxError { - ParseTree tree = new ParseTree( new NonTerminal(74, "type_e") ); + ParseTree tree = new ParseTree( new NonTerminal(84, "type_e") ); Terminal current = ctx.tokens.current(); ctx.nonterminal = "type_e"; if (current == null) { return tree; } - if (rule_first.get(105).contains(terminal_map.get(current.getId()))) { - /* (105) $type_e = :type <=> :lsquare $_gen29 :rsquare -> Type( name=$0, subtype=$2 ) */ - ctx.rule = rules.get(105); + if (rule_first.get(111).contains(terminal_map.get(current.getId()))) { + /* (111) $type_e = :type <=> :lsquare $_gen30 :rsquare -> Type( name=$0, subtype=$2 ) */ + ctx.rule = rules.get(111); tree.setAstTransformation(new AstTransformSubstitution(0)); tree.setNudMorphemeCount(1); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_TYPE)); } - else if (rule_first.get(106).contains(terminal_map.get(current.getId()))) { - /* (106) $type_e = :type */ - ctx.rule = rules.get(106); + else if (rule_first.get(112).contains(terminal_map.get(current.getId()))) { + /* (112) $type_e = :type */ + ctx.rule = rules.get(112); tree.setAstTransformation(new AstTransformSubstitution(0)); tree.setNudMorphemeCount(1); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_TYPE)); @@ -2850,101 +3056,190 @@ else if (rule_first.get(106).contains(terminal_map.get(current.getId()))) { return tree; } private static ParseTree led_type_e(ParseTree left, ParserContext ctx) throws SyntaxError { - ParseTree tree = new ParseTree( new NonTerminal(74, "type_e") ); + ParseTree tree = new ParseTree( new NonTerminal(84, "type_e") ); Terminal current = ctx.tokens.current(); ctx.nonterminal = "type_e"; int modifier; - if (current.getId() == 51) { - /* $type_e = :type <=> :lsquare $_gen29 :rsquare -> Type( name=$0, subtype=$2 ) */ - ctx.rule = rules.get(105); + if (current.getId() == 35) { + /* $type_e = :type <=> :lsquare $_gen30 :rsquare -> Type( name=$0, subtype=$2 ) */ + ctx.rule = rules.get(111); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("name", 0); parameters.put("subtype", 2); tree.setAstTransformation(new AstTransformNodeCreator("Type", parameters)); tree.add(left); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_LSQUARE)); - tree.add(parse__gen29(ctx)); + tree.add(parse__gen30(ctx)); tree.add(expect(ctx, WdlTerminalIdentifier.TERMINAL_RSQUARE)); return tree; } return tree; } - public ParseTree parse__gen16(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen5(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen16(ctx); + return parse__gen5(ctx); } - private static ParseTree parse__gen16(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen5(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; int rule = (current != null) ? table[0][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(58, "_gen16")); - ctx.nonterminal = "_gen16"; + ParseTree tree = new ParseTree( new NonTerminal(56, "_gen5")); + ctx.nonterminal = "_gen5"; tree.setList(true); if ( current != null && - !nonterminal_first.get(58).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(58).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(56).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(56).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 51) { - /* $_gen16 = $output_kv $_gen17 */ - ctx.rule = rules.get(51); + if (rule == 15) { + /* $_gen5 = $declaration $_gen6 */ + ctx.rule = rules.get(15); tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_output_kv(ctx); + subtree = parse_declaration(ctx); tree.add(subtree); - subtree = parse__gen17(ctx); + subtree = parse__gen6(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse__gen5(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen0(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen5(ctx); + return parse__gen0(ctx); } - private static ParseTree parse__gen5(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen0(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; int rule = (current != null) ? table[1][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(59, "_gen5")); - ctx.nonterminal = "_gen5"; + ParseTree tree = new ParseTree( new NonTerminal(57, "_gen0")); + ctx.nonterminal = "_gen0"; tree.setList(true); if ( current != null && - !nonterminal_first.get(59).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(59).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(57).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(57).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 15) { - /* $_gen5 = $declaration $_gen6 */ - ctx.rule = rules.get(15); + if (rule == 0) { + /* $_gen0 = $import $_gen1 */ + ctx.rule = rules.get(0); tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_declaration(ctx); + subtree = parse_import(ctx); tree.add(subtree); - subtree = parse__gen6(ctx); + subtree = parse__gen1(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse__gen4(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_workflow(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen4(ctx); + return parse_workflow(ctx); } - private static ParseTree parse__gen4(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_workflow(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; int rule = (current != null) ? table[2][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(60, "_gen4")); - ctx.nonterminal = "_gen4"; + ParseTree tree = new ParseTree( new NonTerminal(58, "workflow")); + ctx.nonterminal = "workflow"; + tree.setList(false); + if (current == null) { + throw new SyntaxError(ctx.error_formatter.unexpectedEof( + "workflow", + nonterminal_first.get(58), + nonterminal_rules.get(58) + )); + } + if (rule == 70) { + /* $workflow = :workflow :identifier :lbrace $_gen19 :rbrace -> Workflow( name=$1, body=$3 ) */ + ctx.rule = rules.get(70); + LinkedHashMap parameters = new LinkedHashMap(); + parameters.put("name", 1); + parameters.put("body", 3); + tree.setAstTransformation(new AstTransformNodeCreator("Workflow", parameters)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_WORKFLOW); + tree.add(next); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER); + tree.add(next); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LBRACE); + tree.add(next); + subtree = parse__gen19(ctx); + tree.add(subtree); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RBRACE); + tree.add(next); + return tree; + } + throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( + "workflow", + current, + nonterminal_first.get(58), + rules.get(70) + )); + } + public ParseTree parse_call(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); + return parse_call(ctx); + } + private static ParseTree parse_call(ParserContext ctx) throws SyntaxError { + Terminal current = ctx.tokens.current(); + Terminal next; + ParseTree subtree; + int rule = (current != null) ? table[3][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(59, "call")); + ctx.nonterminal = "call"; tree.setList(false); + if (current == null) { + throw new SyntaxError(ctx.error_formatter.unexpectedEof( + "call", + nonterminal_first.get(59), + nonterminal_rules.get(59) + )); + } + if (rule == 81) { + /* $call = :call :fqn $_gen21 $_gen22 -> Call( task=$1, alias=$2, body=$3 ) */ + ctx.rule = rules.get(81); + LinkedHashMap parameters = new LinkedHashMap(); + parameters.put("task", 1); + parameters.put("alias", 2); + parameters.put("body", 3); + tree.setAstTransformation(new AstTransformNodeCreator("Call", parameters)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_CALL); + tree.add(next); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_FQN); + tree.add(next); + subtree = parse__gen21(ctx); + tree.add(subtree); + subtree = parse__gen22(ctx); + tree.add(subtree); + return tree; + } + throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( + "call", + current, + nonterminal_first.get(59), + rules.get(81) + )); + } + public ParseTree parse__gen23(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); + return parse__gen23(ctx); + } + private static ParseTree parse__gen23(ParserContext ctx) throws SyntaxError { + Terminal current = ctx.tokens.current(); + Terminal next; + ParseTree subtree; + int rule = (current != null) ? table[4][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(60, "_gen23")); + ctx.nonterminal = "_gen23"; + tree.setList(true); if ( current != null && !nonterminal_first.get(60).contains(terminal_map.get(current.getId())) && nonterminal_follow.get(60).contains(terminal_map.get(current.getId())) ) { @@ -2953,125 +3248,419 @@ private static ParseTree parse__gen4(ParserContext ctx) throws SyntaxError { if (current == null) { return tree; } - if (rule == 11) { - /* $_gen4 = $import_namespace */ - ctx.rule = rules.get(11); - tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_import_namespace(ctx); + if (rule == 82) { + /* $_gen23 = $call_input $_gen24 */ + ctx.rule = rules.get(82); + tree.setAstTransformation(new AstTransformSubstitution(0)); + subtree = parse_call_input(ctx); + tree.add(subtree); + subtree = parse__gen24(ctx); + tree.add(subtree); + return tree; + } + return tree; + } + public ParseTree parse_wf_output(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); + return parse_wf_output(ctx); + } + private static ParseTree parse_wf_output(ParserContext ctx) throws SyntaxError { + Terminal current = ctx.tokens.current(); + Terminal next; + ParseTree subtree; + int rule = (current != null) ? table[5][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(61, "wf_output")); + ctx.nonterminal = "wf_output"; + tree.setList(false); + if (current == null) { + throw new SyntaxError(ctx.error_formatter.unexpectedEof( + "wf_output", + nonterminal_first.get(61), + nonterminal_rules.get(61) + )); + } + if (rule == 101) { + /* $wf_output = :fqn $_gen29 -> WorkflowOutput( fqn=$0, wildcard=$1 ) */ + ctx.rule = rules.get(101); + LinkedHashMap parameters = new LinkedHashMap(); + parameters.put("fqn", 0); + parameters.put("wildcard", 1); + tree.setAstTransformation(new AstTransformNodeCreator("WorkflowOutput", parameters)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_FQN); + tree.add(next); + subtree = parse__gen29(ctx); + tree.add(subtree); + return tree; + } + throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( + "wf_output", + current, + nonterminal_first.get(61), + rules.get(101) + )); + } + public ParseTree parse__gen32(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); + return parse__gen32(ctx); + } + private static ParseTree parse__gen32(ParserContext ctx) throws SyntaxError { + Terminal current = ctx.tokens.current(); + Terminal next; + ParseTree subtree; + int rule = (current != null) ? table[6][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(62, "_gen32")); + ctx.nonterminal = "_gen32"; + tree.setList(true); + if ( current != null && + !nonterminal_first.get(62).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(62).contains(terminal_map.get(current.getId())) ) { + return tree; + } + if (current == null) { + return tree; + } + if (rule == 129) { + /* $_gen32 = $e $_gen33 */ + ctx.rule = rules.get(129); + tree.setAstTransformation(new AstTransformSubstitution(0)); + subtree = parse_e(ctx); + tree.add(subtree); + subtree = parse__gen33(ctx); + tree.add(subtree); + return tree; + } + return tree; + } + public ParseTree parse__gen9(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); + return parse__gen9(ctx); + } + private static ParseTree parse__gen9(ParserContext ctx) throws SyntaxError { + Terminal current = ctx.tokens.current(); + Terminal next; + ParseTree subtree; + int rule = (current != null) ? table[7][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(63, "_gen9")); + ctx.nonterminal = "_gen9"; + tree.setList(true); + if ( current != null && + !nonterminal_first.get(63).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(63).contains(terminal_map.get(current.getId())) ) { + return tree; + } + if (current == null) { + return tree; + } + if (rule == 29) { + /* $_gen9 = $command_part $_gen10 */ + ctx.rule = rules.get(29); + tree.setAstTransformation(new AstTransformSubstitution(0)); + subtree = parse_command_part(ctx); + tree.add(subtree); + subtree = parse__gen10(ctx); + tree.add(subtree); + return tree; + } + return tree; + } + public ParseTree parse__gen3(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); + return parse__gen3(ctx); + } + private static ParseTree parse__gen3(ParserContext ctx) throws SyntaxError { + Terminal current = ctx.tokens.current(); + Terminal next; + ParseTree subtree; + int rule = (current != null) ? table[8][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(64, "_gen3")); + ctx.nonterminal = "_gen3"; + tree.setList(true); + if ( current != null && + !nonterminal_first.get(64).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(64).contains(terminal_map.get(current.getId())) ) { + return tree; + } + if (current == null) { + return tree; + } + if (rule == 5) { + /* $_gen3 = $workflow_or_task $_gen3 */ + ctx.rule = rules.get(5); + tree.setAstTransformation(new AstTransformSubstitution(0)); + subtree = parse_workflow_or_task(ctx); + tree.add(subtree); + subtree = parse__gen3(ctx); + tree.add(subtree); + return tree; + } + return tree; + } + public ParseTree parse_kv(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); + return parse_kv(ctx); + } + private static ParseTree parse_kv(ParserContext ctx) throws SyntaxError { + Terminal current = ctx.tokens.current(); + Terminal next; + ParseTree subtree; + int rule = (current != null) ? table[9][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(65, "kv")); + ctx.nonterminal = "kv"; + tree.setList(false); + if (current == null) { + throw new SyntaxError(ctx.error_formatter.unexpectedEof( + "kv", + nonterminal_first.get(65), + nonterminal_rules.get(65) + )); + } + if (rule == 56) { + /* $kv = :identifier :colon $e -> RuntimeAttribute( key=$0, value=$2 ) */ + ctx.rule = rules.get(56); + LinkedHashMap parameters = new LinkedHashMap(); + parameters.put("key", 0); + parameters.put("value", 2); + tree.setAstTransformation(new AstTransformNodeCreator("RuntimeAttribute", parameters)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER); + tree.add(next); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_COLON); + tree.add(next); + subtree = parse_e(ctx); + tree.add(subtree); + return tree; + } + throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( + "kv", + current, + nonterminal_first.get(65), + rules.get(56) + )); + } + public ParseTree parse__gen26(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); + return parse__gen26(ctx); + } + private static ParseTree parse__gen26(ParserContext ctx) throws SyntaxError { + Terminal current = ctx.tokens.current(); + Terminal next; + ParseTree subtree; + int rule = (current != null) ? table[10][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(66, "_gen26")); + ctx.nonterminal = "_gen26"; + tree.setList(true); + if ( current != null && + !nonterminal_first.get(66).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(66).contains(terminal_map.get(current.getId())) ) { + return tree; + } + if (current == null) { + return tree; + } + if (rule == 88) { + /* $_gen26 = :comma $mapping $_gen26 */ + ctx.rule = rules.get(88); + tree.setAstTransformation(new AstTransformSubstitution(0)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_COMMA); + tree.add(next); + tree.setListSeparator(next); + subtree = parse_mapping(ctx); + tree.add(subtree); + subtree = parse__gen26(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse__gen22(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_task(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); + return parse_task(ctx); + } + private static ParseTree parse_task(ParserContext ctx) throws SyntaxError { + Terminal current = ctx.tokens.current(); + Terminal next; + ParseTree subtree; + int rule = (current != null) ? table[11][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(67, "task")); + ctx.nonterminal = "task"; + tree.setList(false); + if (current == null) { + throw new SyntaxError(ctx.error_formatter.unexpectedEof( + "task", + nonterminal_first.get(67), + nonterminal_rules.get(67) + )); + } + if (rule == 23) { + /* $task = :task :identifier :lbrace $_gen5 $_gen7 :rbrace -> Task( name=$1, declarations=$3, sections=$4 ) */ + ctx.rule = rules.get(23); + LinkedHashMap parameters = new LinkedHashMap(); + parameters.put("name", 1); + parameters.put("declarations", 3); + parameters.put("sections", 4); + tree.setAstTransformation(new AstTransformNodeCreator("Task", parameters)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_TASK); + tree.add(next); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER); + tree.add(next); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LBRACE); + tree.add(next); + subtree = parse__gen5(ctx); + tree.add(subtree); + subtree = parse__gen7(ctx); + tree.add(subtree); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RBRACE); + tree.add(next); + return tree; + } + throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( + "task", + current, + nonterminal_first.get(67), + rules.get(23) + )); + } + public ParseTree parse_cmd_param(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); + return parse_cmd_param(ctx); + } + private static ParseTree parse_cmd_param(ParserContext ctx) throws SyntaxError { + Terminal current = ctx.tokens.current(); + Terminal next; + ParseTree subtree; + int rule = (current != null) ? table[12][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(68, "cmd_param")); + ctx.nonterminal = "cmd_param"; + tree.setList(false); + if (current == null) { + throw new SyntaxError(ctx.error_formatter.unexpectedEof( + "cmd_param", + nonterminal_first.get(68), + nonterminal_rules.get(68) + )); + } + if (rule == 40) { + /* $cmd_param = :cmd_param_start $_gen11 $e :cmd_param_end -> CommandParameter( attributes=$1, expr=$2 ) */ + ctx.rule = rules.get(40); + LinkedHashMap parameters = new LinkedHashMap(); + parameters.put("attributes", 1); + parameters.put("expr", 2); + tree.setAstTransformation(new AstTransformNodeCreator("CommandParameter", parameters)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_CMD_PARAM_START); + tree.add(next); + subtree = parse__gen11(ctx); + tree.add(subtree); + subtree = parse_e(ctx); + tree.add(subtree); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_CMD_PARAM_END); + tree.add(next); + return tree; + } + throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( + "cmd_param", + current, + nonterminal_first.get(68), + rules.get(40) + )); + } + public ParseTree parse_alias(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); + return parse_alias(ctx); + } + private static ParseTree parse_alias(ParserContext ctx) throws SyntaxError { + Terminal current = ctx.tokens.current(); + Terminal next; + ParseTree subtree; + int rule = (current != null) ? table[13][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(69, "alias")); + ctx.nonterminal = "alias"; + tree.setList(false); + if (current == null) { + throw new SyntaxError(ctx.error_formatter.unexpectedEof( + "alias", + nonterminal_first.get(69), + nonterminal_rules.get(69) + )); + } + if (rule == 93) { + /* $alias = :as :identifier -> $1 */ + ctx.rule = rules.get(93); + tree.setAstTransformation(new AstTransformSubstitution(1)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_AS); + tree.add(next); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER); + tree.add(next); + return tree; + } + throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( + "alias", + current, + nonterminal_first.get(69), + rules.get(93) + )); + } + public ParseTree parse__gen10(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen22(ctx); + return parse__gen10(ctx); } - private static ParseTree parse__gen22(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen10(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[3][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(61, "_gen22")); - ctx.nonterminal = "_gen22"; - tree.setList(false); + int rule = (current != null) ? table[14][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(70, "_gen10")); + ctx.nonterminal = "_gen10"; + tree.setList(true); if ( current != null && - !nonterminal_first.get(61).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(61).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(70).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(70).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 76) { - /* $_gen22 = $alias */ - ctx.rule = rules.get(76); + if (rule == 30) { + /* $_gen10 = $command_part $_gen10 */ + ctx.rule = rules.get(30); tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_alias(ctx); + subtree = parse_command_part(ctx); + tree.add(subtree); + subtree = parse__gen10(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse_workflow_or_task(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen15(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_workflow_or_task(ctx); + return parse__gen15(ctx); } - private static ParseTree parse_workflow_or_task(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen15(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[4][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(62, "workflow_or_task")); - ctx.nonterminal = "workflow_or_task"; - tree.setList(false); - if (current == null) { - throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "workflow_or_task", - nonterminal_first.get(62), - nonterminal_rules.get(62) - )); + int rule = (current != null) ? table[15][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(71, "_gen15")); + ctx.nonterminal = "_gen15"; + tree.setList(true); + if ( current != null && + !nonterminal_first.get(71).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(71).contains(terminal_map.get(current.getId())) ) { + return tree; } - if (rule == 9) { - /* $workflow_or_task = $workflow */ - ctx.rule = rules.get(9); - tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_workflow(ctx); - tree.add(subtree); + if (current == null) { return tree; } - else if (rule == 10) { - /* $workflow_or_task = $task */ - ctx.rule = rules.get(10); + if (rule == 51) { + /* $_gen15 = $kv $_gen16 */ + ctx.rule = rules.get(51); tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_task(ctx); + subtree = parse_kv(ctx); tree.add(subtree); - return tree; - } - throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "workflow_or_task", - current, - nonterminal_first.get(62), - rules.get(10) - )); - } - public ParseTree parse_meta(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { - ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_meta(ctx); - } - private static ParseTree parse_meta(ParserContext ctx) throws SyntaxError { - Terminal current = ctx.tokens.current(); - Terminal next; - ParseTree subtree; - int rule = (current != null) ? table[5][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(63, "meta")); - ctx.nonterminal = "meta"; - tree.setList(false); - if (current == null) { - throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "meta", - nonterminal_first.get(63), - nonterminal_rules.get(63) - )); - } - if (rule == 59) { - /* $meta = :meta $map -> Meta( map=$1 ) */ - ctx.rule = rules.get(59); - LinkedHashMap parameters = new LinkedHashMap(); - parameters.put("map", 1); - tree.setAstTransformation(new AstTransformNodeCreator("Meta", parameters)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_META); - tree.add(next); - subtree = parse_map(ctx); + subtree = parse__gen16(ctx); tree.add(subtree); return tree; } - throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "meta", - current, - nonterminal_first.get(63), - rules.get(59) - )); + return tree; } public ParseTree parse_wf_body_element(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); @@ -3081,15 +3670,15 @@ private static ParseTree parse_wf_body_element(ParserContext ctx) throws SyntaxE Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[6][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(64, "wf_body_element")); + int rule = (current != null) ? table[16][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(72, "wf_body_element")); ctx.nonterminal = "wf_body_element"; tree.setList(false); if (current == null) { throw new SyntaxError(ctx.error_formatter.unexpectedEof( "wf_body_element", - nonterminal_first.get(64), - nonterminal_rules.get(64) + nonterminal_first.get(72), + nonterminal_rules.get(72) )); } if (rule == 71) { @@ -3132,540 +3721,363 @@ else if (rule == 75) { tree.add(subtree); return tree; } - throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "wf_body_element", - current, - nonterminal_first.get(64), - rules.get(75) - )); - } - public ParseTree parse_runtime(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { - ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_runtime(ctx); - } - private static ParseTree parse_runtime(ParserContext ctx) throws SyntaxError { - Terminal current = ctx.tokens.current(); - Terminal next; - ParseTree subtree; - int rule = (current != null) ? table[7][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(65, "runtime")); - ctx.nonterminal = "runtime"; - tree.setList(false); - if (current == null) { - throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "runtime", - nonterminal_first.get(65), - nonterminal_rules.get(65) - )); - } - if (rule == 57) { - /* $runtime = :runtime $map -> Runtime( map=$1 ) */ - ctx.rule = rules.get(57); - LinkedHashMap parameters = new LinkedHashMap(); - parameters.put("map", 1); - tree.setAstTransformation(new AstTransformNodeCreator("Runtime", parameters)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RUNTIME); - tree.add(next); - subtree = parse_map(ctx); + else if (rule == 76) { + /* $wf_body_element = $wf_outputs */ + ctx.rule = rules.get(76); + tree.setAstTransformation(new AstTransformSubstitution(0)); + subtree = parse_wf_outputs(ctx); tree.add(subtree); return tree; } throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "runtime", + "wf_body_element", current, - nonterminal_first.get(65), - rules.get(57) + nonterminal_first.get(72), + rules.get(76) )); } - public ParseTree parse_while_loop(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_cmd_param_kv(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_while_loop(ctx); + return parse_cmd_param_kv(ctx); } - private static ParseTree parse_while_loop(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_cmd_param_kv(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[8][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(66, "while_loop")); - ctx.nonterminal = "while_loop"; + int rule = (current != null) ? table[17][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(73, "cmd_param_kv")); + ctx.nonterminal = "cmd_param_kv"; tree.setList(false); if (current == null) { throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "while_loop", - nonterminal_first.get(66), - nonterminal_rules.get(66) + "cmd_param_kv", + nonterminal_first.get(73), + nonterminal_rules.get(73) )); } - if (rule == 93) { - /* $while_loop = :while :lparen $e :rparen :lbrace $_gen20 :rbrace -> WhileLoop( expression=$2, body=$5 ) */ - ctx.rule = rules.get(93); + if (rule == 41) { + /* $cmd_param_kv = :cmd_attr_hint :identifier :equal $e -> CommandParameterAttr( key=$1, value=$3 ) */ + ctx.rule = rules.get(41); LinkedHashMap parameters = new LinkedHashMap(); - parameters.put("expression", 2); - parameters.put("body", 5); - tree.setAstTransformation(new AstTransformNodeCreator("WhileLoop", parameters)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_WHILE); - tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LPAREN); - tree.add(next); - subtree = parse_e(ctx); - tree.add(subtree); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RPAREN); - tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LBRACE); + parameters.put("key", 1); + parameters.put("value", 3); + tree.setAstTransformation(new AstTransformNodeCreator("CommandParameterAttr", parameters)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_CMD_ATTR_HINT); tree.add(next); - subtree = parse__gen20(ctx); - tree.add(subtree); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RBRACE); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER); tree.add(next); - return tree; - } - throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "while_loop", - current, - nonterminal_first.get(66), - rules.get(93) - )); - } - public ParseTree parse__gen18(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { - ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen18(ctx); - } - private static ParseTree parse__gen18(ParserContext ctx) throws SyntaxError { - Terminal current = ctx.tokens.current(); - Terminal next; - ParseTree subtree; - int rule = (current != null) ? table[9][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(67, "_gen18")); - ctx.nonterminal = "_gen18"; - tree.setList(true); - if ( current != null && - !nonterminal_first.get(67).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(67).contains(terminal_map.get(current.getId())) ) { - return tree; - } - if (current == null) { - return tree; - } - if (rule == 60) { - /* $_gen18 = $kv $_gen19 */ - ctx.rule = rules.get(60); - tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_kv(ctx); - tree.add(subtree); - subtree = parse__gen19(ctx); - tree.add(subtree); - return tree; - } - return tree; - } - public ParseTree parse__gen34(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { - ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen34(ctx); - } - private static ParseTree parse__gen34(ParserContext ctx) throws SyntaxError { - Terminal current = ctx.tokens.current(); - Terminal next; - ParseTree subtree; - int rule = (current != null) ? table[10][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(68, "_gen34")); - ctx.nonterminal = "_gen34"; - tree.setList(true); - if ( current != null && - !nonterminal_first.get(68).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(68).contains(terminal_map.get(current.getId())) ) { - return tree; - } - if (current == null) { - return tree; - } - if (rule == 131) { - /* $_gen34 = :comma $object_kv $_gen34 */ - ctx.rule = rules.get(131); - tree.setAstTransformation(new AstTransformSubstitution(0)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_COMMA); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_EQUAL); tree.add(next); - tree.setListSeparator(next); - subtree = parse_object_kv(ctx); - tree.add(subtree); - subtree = parse__gen34(ctx); - tree.add(subtree); - return tree; - } - return tree; - } - public ParseTree parse__gen25(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { - ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen25(ctx); - } - private static ParseTree parse__gen25(ParserContext ctx) throws SyntaxError { - Terminal current = ctx.tokens.current(); - Terminal next; - ParseTree subtree; - int rule = (current != null) ? table[11][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(69, "_gen25")); - ctx.nonterminal = "_gen25"; - tree.setList(true); - if ( current != null && - !nonterminal_first.get(69).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(69).contains(terminal_map.get(current.getId())) ) { - return tree; - } - if (current == null) { - return tree; - } - if (rule == 82) { - /* $_gen25 = $call_input $_gen25 */ - ctx.rule = rules.get(82); - tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_call_input(ctx); - tree.add(subtree); - subtree = parse__gen25(ctx); + subtree = parse_e(ctx); tree.add(subtree); return tree; } - return tree; + throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( + "cmd_param_kv", + current, + nonterminal_first.get(73), + rules.get(41) + )); } - public ParseTree parse_call(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_command_part(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_call(ctx); + return parse_command_part(ctx); } - private static ParseTree parse_call(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_command_part(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[12][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(70, "call")); - ctx.nonterminal = "call"; + int rule = (current != null) ? table[18][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(74, "command_part")); + ctx.nonterminal = "command_part"; tree.setList(false); if (current == null) { throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "call", - nonterminal_first.get(70), - nonterminal_rules.get(70) + "command_part", + nonterminal_first.get(74), + nonterminal_rules.get(74) )); } - if (rule == 80) { - /* $call = :call :ns_identifier $_gen22 $_gen23 -> Call( task=$1, alias=$2, body=$3 ) */ - ctx.rule = rules.get(80); - LinkedHashMap parameters = new LinkedHashMap(); - parameters.put("task", 1); - parameters.put("alias", 2); - parameters.put("body", 3); - tree.setAstTransformation(new AstTransformNodeCreator("Call", parameters)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_CALL); - tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_NS_IDENTIFIER); + if (rule == 34) { + /* $command_part = :cmd_part */ + ctx.rule = rules.get(34); + tree.setAstTransformation(new AstTransformSubstitution(0)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_CMD_PART); tree.add(next); - subtree = parse__gen22(ctx); - tree.add(subtree); - subtree = parse__gen23(ctx); + return tree; + } + else if (rule == 35) { + /* $command_part = $cmd_param */ + ctx.rule = rules.get(35); + tree.setAstTransformation(new AstTransformSubstitution(0)); + subtree = parse_cmd_param(ctx); tree.add(subtree); return tree; } throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "call", + "command_part", current, - nonterminal_first.get(70), - rules.get(80) + nonterminal_first.get(74), + rules.get(35) )); } - public ParseTree parse_parameter_meta(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_call_body(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_parameter_meta(ctx); + return parse_call_body(ctx); } - private static ParseTree parse_parameter_meta(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_call_body(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[13][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(71, "parameter_meta")); - ctx.nonterminal = "parameter_meta"; + int rule = (current != null) ? table[19][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(75, "call_body")); + ctx.nonterminal = "call_body"; tree.setList(false); if (current == null) { throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "parameter_meta", - nonterminal_first.get(71), - nonterminal_rules.get(71) + "call_body", + nonterminal_first.get(75), + nonterminal_rules.get(75) )); } - if (rule == 58) { - /* $parameter_meta = :parameter_meta $map -> ParameterMeta( map=$1 ) */ - ctx.rule = rules.get(58); + if (rule == 86) { + /* $call_body = :lbrace $_gen5 $_gen23 :rbrace -> CallBody( declarations=$1, io=$2 ) */ + ctx.rule = rules.get(86); LinkedHashMap parameters = new LinkedHashMap(); - parameters.put("map", 1); - tree.setAstTransformation(new AstTransformNodeCreator("ParameterMeta", parameters)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_PARAMETER_META); + parameters.put("declarations", 1); + parameters.put("io", 2); + tree.setAstTransformation(new AstTransformNodeCreator("CallBody", parameters)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LBRACE); tree.add(next); - subtree = parse_map(ctx); + subtree = parse__gen5(ctx); + tree.add(subtree); + subtree = parse__gen23(ctx); tree.add(subtree); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RBRACE); + tree.add(next); return tree; } throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "parameter_meta", + "call_body", current, - nonterminal_first.get(71), - rules.get(58) + nonterminal_first.get(75), + rules.get(86) )); } - public ParseTree parse__gen3(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen29(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen3(ctx); + return parse__gen29(ctx); } - private static ParseTree parse__gen3(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen29(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[14][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(72, "_gen3")); - ctx.nonterminal = "_gen3"; - tree.setList(true); + int rule = (current != null) ? table[20][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(76, "_gen29")); + ctx.nonterminal = "_gen29"; + tree.setList(false); if ( current != null && - !nonterminal_first.get(72).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(72).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(76).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(76).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 5) { - /* $_gen3 = $workflow_or_task $_gen3 */ - ctx.rule = rules.get(5); + if (rule == 99) { + /* $_gen29 = $wf_output_wildcard */ + ctx.rule = rules.get(99); tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_workflow_or_task(ctx); - tree.add(subtree); - subtree = parse__gen3(ctx); + subtree = parse_wf_output_wildcard(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse_declaration(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { - ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_declaration(ctx); - } - private static ParseTree parse_declaration(ParserContext ctx) throws SyntaxError { - Terminal current = ctx.tokens.current(); - Terminal next; - ParseTree subtree; - int rule = (current != null) ? table[15][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(73, "declaration")); - ctx.nonterminal = "declaration"; - tree.setList(false); - if (current == null) { - throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "declaration", - nonterminal_first.get(73), - nonterminal_rules.get(73) - )); - } - if (rule == 98) { - /* $declaration = $type_e :identifier $_gen28 -> Declaration( type=$0, name=$1, expression=$2 ) */ - ctx.rule = rules.get(98); - LinkedHashMap parameters = new LinkedHashMap(); - parameters.put("type", 0); - parameters.put("name", 1); - parameters.put("expression", 2); - tree.setAstTransformation(new AstTransformNodeCreator("Declaration", parameters)); - subtree = parse_type_e(ctx); - tree.add(subtree); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER); - tree.add(next); - subtree = parse__gen28(ctx); - tree.add(subtree); - return tree; - } - throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "declaration", - current, - nonterminal_first.get(73), - rules.get(98) - )); - } - public ParseTree parse__gen24(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen28(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen24(ctx); + return parse__gen28(ctx); } - private static ParseTree parse__gen24(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen28(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[17][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(75, "_gen24")); - ctx.nonterminal = "_gen24"; + int rule = (current != null) ? table[21][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(77, "_gen28")); + ctx.nonterminal = "_gen28"; tree.setList(true); if ( current != null && - !nonterminal_first.get(75).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(75).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(77).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(77).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 81) { - /* $_gen24 = $call_input $_gen25 */ - ctx.rule = rules.get(81); + if (rule == 95) { + /* $_gen28 = :comma $wf_output $_gen28 */ + ctx.rule = rules.get(95); tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_call_input(ctx); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_COMMA); + tree.add(next); + tree.setListSeparator(next); + subtree = parse_wf_output(ctx); tree.add(subtree); - subtree = parse__gen25(ctx); + subtree = parse__gen28(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse_setter(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_postfix_quantifier(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_setter(ctx); + return parse_postfix_quantifier(ctx); } - private static ParseTree parse_setter(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_postfix_quantifier(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[18][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(76, "setter")); - ctx.nonterminal = "setter"; + int rule = (current != null) ? table[22][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(78, "postfix_quantifier")); + ctx.nonterminal = "postfix_quantifier"; tree.setList(false); if (current == null) { throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "setter", - nonterminal_first.get(76), - nonterminal_rules.get(76) + "postfix_quantifier", + nonterminal_first.get(78), + nonterminal_rules.get(78) )); } - if (rule == 99) { - /* $setter = :equal $e -> $1 */ - ctx.rule = rules.get(99); - tree.setAstTransformation(new AstTransformSubstitution(1)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_EQUAL); + if (rule == 63) { + /* $postfix_quantifier = :qmark */ + ctx.rule = rules.get(63); + tree.setAstTransformation(new AstTransformSubstitution(0)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_QMARK); + tree.add(next); + return tree; + } + else if (rule == 64) { + /* $postfix_quantifier = :plus */ + ctx.rule = rules.get(64); + tree.setAstTransformation(new AstTransformSubstitution(0)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_PLUS); tree.add(next); - subtree = parse_e(ctx); - tree.add(subtree); return tree; } throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "setter", + "postfix_quantifier", current, - nonterminal_first.get(76), - rules.get(99) + nonterminal_first.get(78), + rules.get(64) )); } - public ParseTree parse_cmd_param(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_workflow_or_task(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_cmd_param(ctx); + return parse_workflow_or_task(ctx); } - private static ParseTree parse_cmd_param(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_workflow_or_task(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[19][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(77, "cmd_param")); - ctx.nonterminal = "cmd_param"; + int rule = (current != null) ? table[23][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(79, "workflow_or_task")); + ctx.nonterminal = "workflow_or_task"; tree.setList(false); if (current == null) { throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "cmd_param", - nonterminal_first.get(77), - nonterminal_rules.get(77) + "workflow_or_task", + nonterminal_first.get(79), + nonterminal_rules.get(79) )); } - if (rule == 46) { - /* $cmd_param = :cmd_param_start $_gen11 $_gen13 $_gen14 :identifier $_gen15 :cmd_param_end -> CommandParameter( name=$4, type=$3, prefix=$2, attributes=$1, postfix=$5 ) */ - ctx.rule = rules.get(46); - LinkedHashMap parameters = new LinkedHashMap(); - parameters.put("name", 4); - parameters.put("type", 3); - parameters.put("prefix", 2); - parameters.put("attributes", 1); - parameters.put("postfix", 5); - tree.setAstTransformation(new AstTransformNodeCreator("CommandParameter", parameters)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_CMD_PARAM_START); - tree.add(next); - subtree = parse__gen11(ctx); - tree.add(subtree); - subtree = parse__gen13(ctx); - tree.add(subtree); - subtree = parse__gen14(ctx); + if (rule == 9) { + /* $workflow_or_task = $workflow */ + ctx.rule = rules.get(9); + tree.setAstTransformation(new AstTransformSubstitution(0)); + subtree = parse_workflow(ctx); tree.add(subtree); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER); - tree.add(next); - subtree = parse__gen15(ctx); + return tree; + } + else if (rule == 10) { + /* $workflow_or_task = $task */ + ctx.rule = rules.get(10); + tree.setAstTransformation(new AstTransformSubstitution(0)); + subtree = parse_task(ctx); tree.add(subtree); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_CMD_PARAM_END); - tree.add(next); return tree; } throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "cmd_param", + "workflow_or_task", current, - nonterminal_first.get(77), - rules.get(46) + nonterminal_first.get(79), + rules.get(10) )); } - public ParseTree parse_map(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_parameter_meta(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_map(ctx); + return parse_parameter_meta(ctx); } - private static ParseTree parse_map(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_parameter_meta(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[20][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(78, "map")); - ctx.nonterminal = "map"; + int rule = (current != null) ? table[24][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(80, "parameter_meta")); + ctx.nonterminal = "parameter_meta"; tree.setList(false); if (current == null) { throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "map", - nonterminal_first.get(78), - nonterminal_rules.get(78) + "parameter_meta", + nonterminal_first.get(80), + nonterminal_rules.get(80) )); } - if (rule == 64) { - /* $map = :lbrace $_gen18 :rbrace -> $1 */ - ctx.rule = rules.get(64); - tree.setAstTransformation(new AstTransformSubstitution(1)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LBRACE); + if (rule == 49) { + /* $parameter_meta = :parameter_meta $map -> ParameterMeta( map=$1 ) */ + ctx.rule = rules.get(49); + LinkedHashMap parameters = new LinkedHashMap(); + parameters.put("map", 1); + tree.setAstTransformation(new AstTransformNodeCreator("ParameterMeta", parameters)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_PARAMETER_META); tree.add(next); - subtree = parse__gen18(ctx); + subtree = parse_map(ctx); tree.add(subtree); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RBRACE); - tree.add(next); return tree; } throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "map", + "parameter_meta", current, - nonterminal_first.get(78), - rules.get(64) + nonterminal_first.get(80), + rules.get(49) )); } - public ParseTree parse__gen29(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen36(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen29(ctx); + return parse__gen36(ctx); } - private static ParseTree parse__gen29(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen36(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[21][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(79, "_gen29")); - ctx.nonterminal = "_gen29"; + int rule = (current != null) ? table[25][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(81, "_gen36")); + ctx.nonterminal = "_gen36"; tree.setList(true); if ( current != null && - !nonterminal_first.get(79).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(79).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(81).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(81).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 101) { - /* $_gen29 = $type_e $_gen30 */ - ctx.rule = rules.get(101); + if (rule == 142) { + /* $_gen36 = $map_kv $_gen37 */ + ctx.rule = rules.get(142); tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_type_e(ctx); + subtree = parse_map_kv(ctx); tree.add(subtree); - subtree = parse__gen30(ctx); + subtree = parse__gen37(ctx); tree.add(subtree); return tree; } @@ -3679,945 +4091,978 @@ private static ParseTree parse__gen31(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[22][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(80, "_gen31")); + int rule = (current != null) ? table[26][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(82, "_gen31")); ctx.nonterminal = "_gen31"; tree.setList(true); if ( current != null && - !nonterminal_first.get(80).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(80).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(82).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(82).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 123) { - /* $_gen31 = $e $_gen32 */ - ctx.rule = rules.get(123); + if (rule == 108) { + /* $_gen31 = :comma $type_e $_gen31 */ + ctx.rule = rules.get(108); tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_e(ctx); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_COMMA); + tree.add(next); + tree.setListSeparator(next); + subtree = parse_type_e(ctx); tree.add(subtree); - subtree = parse__gen32(ctx); + subtree = parse__gen31(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse_task(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen4(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_task(ctx); + return parse__gen4(ctx); } - private static ParseTree parse_task(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen4(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[23][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(81, "task")); - ctx.nonterminal = "task"; + int rule = (current != null) ? table[27][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(83, "_gen4")); + ctx.nonterminal = "_gen4"; tree.setList(false); + if ( current != null && + !nonterminal_first.get(83).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(83).contains(terminal_map.get(current.getId())) ) { + return tree; + } if (current == null) { - throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "task", - nonterminal_first.get(81), - nonterminal_rules.get(81) - )); + return tree; } - if (rule == 23) { - /* $task = :task :identifier :lbrace $_gen5 $_gen7 :rbrace -> Task( name=$1, declarations=$3, sections=$4 ) */ - ctx.rule = rules.get(23); - LinkedHashMap parameters = new LinkedHashMap(); - parameters.put("name", 1); - parameters.put("declarations", 3); - parameters.put("sections", 4); - tree.setAstTransformation(new AstTransformNodeCreator("Task", parameters)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_TASK); - tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER); - tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LBRACE); - tree.add(next); - subtree = parse__gen5(ctx); - tree.add(subtree); - subtree = parse__gen7(ctx); + if (rule == 11) { + /* $_gen4 = $import_namespace */ + ctx.rule = rules.get(11); + tree.setAstTransformation(new AstTransformSubstitution(0)); + subtree = parse_import_namespace(ctx); tree.add(subtree); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RBRACE); - tree.add(next); return tree; } - throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "task", - current, - nonterminal_first.get(81), - rules.get(23) - )); + return tree; } - public ParseTree parse__gen15(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_runtime(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen15(ctx); + return parse_runtime(ctx); } - private static ParseTree parse__gen15(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_runtime(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[24][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(82, "_gen15")); - ctx.nonterminal = "_gen15"; + int rule = (current != null) ? table[29][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(85, "runtime")); + ctx.nonterminal = "runtime"; tree.setList(false); - if ( current != null && - !nonterminal_first.get(82).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(82).contains(terminal_map.get(current.getId())) ) { - return tree; - } if (current == null) { - return tree; + throw new SyntaxError(ctx.error_formatter.unexpectedEof( + "runtime", + nonterminal_first.get(85), + nonterminal_rules.get(85) + )); } - if (rule == 44) { - /* $_gen15 = $postfix_quantifier */ - ctx.rule = rules.get(44); - tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_postfix_quantifier(ctx); + if (rule == 48) { + /* $runtime = :runtime $map -> Runtime( map=$1 ) */ + ctx.rule = rules.get(48); + LinkedHashMap parameters = new LinkedHashMap(); + parameters.put("map", 1); + tree.setAstTransformation(new AstTransformNodeCreator("Runtime", parameters)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RUNTIME); + tree.add(next); + subtree = parse_map(ctx); tree.add(subtree); return tree; } - return tree; + throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( + "runtime", + current, + nonterminal_first.get(85), + rules.get(48) + )); } - public ParseTree parse_command_part(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_wf_outputs(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_command_part(ctx); + return parse_wf_outputs(ctx); } - private static ParseTree parse_command_part(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_wf_outputs(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[25][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(83, "command_part")); - ctx.nonterminal = "command_part"; + int rule = (current != null) ? table[30][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(86, "wf_outputs")); + ctx.nonterminal = "wf_outputs"; tree.setList(false); if (current == null) { throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "command_part", - nonterminal_first.get(83), - nonterminal_rules.get(83) + "wf_outputs", + nonterminal_first.get(86), + nonterminal_rules.get(86) )); } - if (rule == 34) { - /* $command_part = :cmd_part */ - ctx.rule = rules.get(34); - tree.setAstTransformation(new AstTransformSubstitution(0)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_CMD_PART); + if (rule == 98) { + /* $wf_outputs = :output :lbrace $_gen27 :rbrace -> WorkflowOutputs( outputs=$2 ) */ + ctx.rule = rules.get(98); + LinkedHashMap parameters = new LinkedHashMap(); + parameters.put("outputs", 2); + tree.setAstTransformation(new AstTransformNodeCreator("WorkflowOutputs", parameters)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_OUTPUT); tree.add(next); - return tree; - } - else if (rule == 35) { - /* $command_part = $cmd_param */ - ctx.rule = rules.get(35); - tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_cmd_param(ctx); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LBRACE); + tree.add(next); + subtree = parse__gen27(ctx); tree.add(subtree); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RBRACE); + tree.add(next); return tree; } throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "command_part", + "wf_outputs", current, - nonterminal_first.get(83), - rules.get(35) + nonterminal_first.get(86), + rules.get(98) )); } - public ParseTree parse__gen19(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_while_loop(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen19(ctx); + return parse_while_loop(ctx); } - private static ParseTree parse__gen19(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_while_loop(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[26][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(84, "_gen19")); - ctx.nonterminal = "_gen19"; - tree.setList(true); - if ( current != null && - !nonterminal_first.get(84).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(84).contains(terminal_map.get(current.getId())) ) { - return tree; - } + int rule = (current != null) ? table[31][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(87, "while_loop")); + ctx.nonterminal = "while_loop"; + tree.setList(false); if (current == null) { - return tree; + throw new SyntaxError(ctx.error_formatter.unexpectedEof( + "while_loop", + nonterminal_first.get(87), + nonterminal_rules.get(87) + )); } - if (rule == 61) { - /* $_gen19 = $kv $_gen19 */ - ctx.rule = rules.get(61); - tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_kv(ctx); + if (rule == 103) { + /* $while_loop = :while :lparen $e :rparen :lbrace $_gen19 :rbrace -> WhileLoop( expression=$2, body=$5 ) */ + ctx.rule = rules.get(103); + LinkedHashMap parameters = new LinkedHashMap(); + parameters.put("expression", 2); + parameters.put("body", 5); + tree.setAstTransformation(new AstTransformNodeCreator("WhileLoop", parameters)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_WHILE); + tree.add(next); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LPAREN); + tree.add(next); + subtree = parse_e(ctx); tree.add(subtree); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RPAREN); + tree.add(next); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LBRACE); + tree.add(next); subtree = parse__gen19(ctx); tree.add(subtree); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RBRACE); + tree.add(next); return tree; } - return tree; + throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( + "while_loop", + current, + nonterminal_first.get(87), + rules.get(103) + )); } - public ParseTree parse_kv(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_outputs(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_kv(ctx); + return parse_outputs(ctx); } - private static ParseTree parse_kv(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_outputs(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[27][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(85, "kv")); - ctx.nonterminal = "kv"; + int rule = (current != null) ? table[32][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(88, "outputs")); + ctx.nonterminal = "outputs"; tree.setList(false); if (current == null) { throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "kv", - nonterminal_first.get(85), - nonterminal_rules.get(85) + "outputs", + nonterminal_first.get(88), + nonterminal_rules.get(88) )); } - if (rule == 65) { - /* $kv = :identifier :colon $e -> RuntimeAttribute( key=$0, value=$2 ) */ - ctx.rule = rules.get(65); + if (rule == 46) { + /* $outputs = :output :lbrace $_gen13 :rbrace -> Outputs( attributes=$2 ) */ + ctx.rule = rules.get(46); LinkedHashMap parameters = new LinkedHashMap(); - parameters.put("key", 0); - parameters.put("value", 2); - tree.setAstTransformation(new AstTransformNodeCreator("RuntimeAttribute", parameters)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER); + parameters.put("attributes", 2); + tree.setAstTransformation(new AstTransformNodeCreator("Outputs", parameters)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_OUTPUT); tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_COLON); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LBRACE); tree.add(next); - subtree = parse_e(ctx); + subtree = parse__gen13(ctx); + tree.add(subtree); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RBRACE); + tree.add(next); + return tree; + } + throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( + "outputs", + current, + nonterminal_first.get(88), + rules.get(46) + )); + } + public ParseTree parse__gen16(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); + return parse__gen16(ctx); + } + private static ParseTree parse__gen16(ParserContext ctx) throws SyntaxError { + Terminal current = ctx.tokens.current(); + Terminal next; + ParseTree subtree; + int rule = (current != null) ? table[33][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(89, "_gen16")); + ctx.nonterminal = "_gen16"; + tree.setList(true); + if ( current != null && + !nonterminal_first.get(89).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(89).contains(terminal_map.get(current.getId())) ) { + return tree; + } + if (current == null) { + return tree; + } + if (rule == 52) { + /* $_gen16 = $kv $_gen16 */ + ctx.rule = rules.get(52); + tree.setAstTransformation(new AstTransformSubstitution(0)); + subtree = parse_kv(ctx); + tree.add(subtree); + subtree = parse__gen16(ctx); tree.add(subtree); return tree; } - throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "kv", - current, - nonterminal_first.get(85), - rules.get(65) - )); + return tree; } - public ParseTree parse_call_input(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_object_kv(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_call_input(ctx); + return parse_object_kv(ctx); } - private static ParseTree parse_call_input(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_object_kv(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[28][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(86, "call_input")); - ctx.nonterminal = "call_input"; + int rule = (current != null) ? table[34][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(90, "object_kv")); + ctx.nonterminal = "object_kv"; tree.setList(false); if (current == null) { throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "call_input", - nonterminal_first.get(86), - nonterminal_rules.get(86) + "object_kv", + nonterminal_first.get(90), + nonterminal_rules.get(90) )); } - if (rule == 90) { - /* $call_input = :input :colon $_gen26 -> Inputs( map=$2 ) */ - ctx.rule = rules.get(90); + if (rule == 106) { + /* $object_kv = :identifier :colon $e -> ObjectKV( key=$0, value=$2 ) */ + ctx.rule = rules.get(106); LinkedHashMap parameters = new LinkedHashMap(); - parameters.put("map", 2); - tree.setAstTransformation(new AstTransformNodeCreator("Inputs", parameters)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_INPUT); + parameters.put("key", 0); + parameters.put("value", 2); + tree.setAstTransformation(new AstTransformNodeCreator("ObjectKV", parameters)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER); tree.add(next); next = expect(ctx, WdlTerminalIdentifier.TERMINAL_COLON); tree.add(next); - subtree = parse__gen26(ctx); + subtree = parse_e(ctx); tree.add(subtree); return tree; } throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "call_input", + "object_kv", current, - nonterminal_first.get(86), - rules.get(90) + nonterminal_first.get(90), + rules.get(106) )); } - public ParseTree parse__gen1(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen20(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen1(ctx); + return parse__gen20(ctx); } - private static ParseTree parse__gen1(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen20(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[29][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(87, "_gen1")); - ctx.nonterminal = "_gen1"; + int rule = (current != null) ? table[35][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(91, "_gen20")); + ctx.nonterminal = "_gen20"; tree.setList(true); if ( current != null && - !nonterminal_first.get(87).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(87).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(91).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(91).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 1) { - /* $_gen1 = $import $_gen1 */ - ctx.rule = rules.get(1); + if (rule == 67) { + /* $_gen20 = $wf_body_element $_gen20 */ + ctx.rule = rules.get(67); tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_import(ctx); + subtree = parse_wf_body_element(ctx); tree.add(subtree); - subtree = parse__gen1(ctx); + subtree = parse__gen20(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse_output_kv(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_call_input(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_output_kv(ctx); + return parse_call_input(ctx); } - private static ParseTree parse_output_kv(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_call_input(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[30][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(88, "output_kv")); - ctx.nonterminal = "output_kv"; + int rule = (current != null) ? table[36][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(92, "call_input")); + ctx.nonterminal = "call_input"; tree.setList(false); if (current == null) { throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "output_kv", - nonterminal_first.get(88), - nonterminal_rules.get(88) + "call_input", + nonterminal_first.get(92), + nonterminal_rules.get(92) )); } - if (rule == 56) { - /* $output_kv = $type_e :identifier :equal $e -> Output( type=$0, var=$1, expression=$3 ) */ - ctx.rule = rules.get(56); + if (rule == 91) { + /* $call_input = :input :colon $_gen25 -> Inputs( map=$2 ) */ + ctx.rule = rules.get(91); LinkedHashMap parameters = new LinkedHashMap(); - parameters.put("type", 0); - parameters.put("var", 1); - parameters.put("expression", 3); - tree.setAstTransformation(new AstTransformNodeCreator("Output", parameters)); - subtree = parse_type_e(ctx); - tree.add(subtree); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER); + parameters.put("map", 2); + tree.setAstTransformation(new AstTransformNodeCreator("Inputs", parameters)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_INPUT); tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_EQUAL); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_COLON); tree.add(next); - subtree = parse_e(ctx); + subtree = parse__gen25(ctx); tree.add(subtree); return tree; } throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "output_kv", + "call_input", current, - nonterminal_first.get(88), - rules.get(56) + nonterminal_first.get(92), + rules.get(91) )); } - public ParseTree parse__gen23(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_import(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen23(ctx); + return parse_import(ctx); } - private static ParseTree parse__gen23(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_import(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[31][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(89, "_gen23")); - ctx.nonterminal = "_gen23"; + int rule = (current != null) ? table[37][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(93, "import")); + ctx.nonterminal = "import"; tree.setList(false); - if ( current != null && - !nonterminal_first.get(89).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(89).contains(terminal_map.get(current.getId())) ) { - return tree; - } if (current == null) { - return tree; + throw new SyntaxError(ctx.error_formatter.unexpectedEof( + "import", + nonterminal_first.get(93), + nonterminal_rules.get(93) + )); } - if (rule == 78) { - /* $_gen23 = $call_body */ - ctx.rule = rules.get(78); - tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_call_body(ctx); + if (rule == 13) { + /* $import = :import :string $_gen4 -> Import( uri=$1, namespace=$2 ) */ + ctx.rule = rules.get(13); + LinkedHashMap parameters = new LinkedHashMap(); + parameters.put("uri", 1); + parameters.put("namespace", 2); + tree.setAstTransformation(new AstTransformNodeCreator("Import", parameters)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IMPORT); + tree.add(next); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_STRING); + tree.add(next); + subtree = parse__gen4(ctx); tree.add(subtree); return tree; } - return tree; + throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( + "import", + current, + nonterminal_first.get(93), + rules.get(13) + )); } - public ParseTree parse__gen12(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_document(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen12(ctx); + return parse_document(ctx); } - private static ParseTree parse__gen12(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_document(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[32][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(90, "_gen12")); - ctx.nonterminal = "_gen12"; - tree.setList(true); + int rule = (current != null) ? table[38][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(94, "document")); + ctx.nonterminal = "document"; + tree.setList(false); if ( current != null && - !nonterminal_first.get(90).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(90).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(94).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(94).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 37) { - /* $_gen12 = $cmd_param_kv $_gen12 */ - ctx.rule = rules.get(37); - tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_cmd_param_kv(ctx); + if (rule == 8) { + /* $document = $_gen0 $_gen2 -> Document( imports=$0, definitions=$1 ) */ + ctx.rule = rules.get(8); + LinkedHashMap parameters = new LinkedHashMap(); + parameters.put("imports", 0); + parameters.put("definitions", 1); + tree.setAstTransformation(new AstTransformNodeCreator("Document", parameters)); + subtree = parse__gen0(ctx); tree.add(subtree); - subtree = parse__gen12(ctx); + subtree = parse__gen2(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse__gen14(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen1(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen14(ctx); + return parse__gen1(ctx); } - private static ParseTree parse__gen14(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen1(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[33][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(91, "_gen14")); - ctx.nonterminal = "_gen14"; - tree.setList(false); + int rule = (current != null) ? table[39][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(95, "_gen1")); + ctx.nonterminal = "_gen1"; + tree.setList(true); if ( current != null && - !nonterminal_first.get(91).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(91).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(95).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(95).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 42) { - /* $_gen14 = $type_e */ - ctx.rule = rules.get(42); + if (rule == 1) { + /* $_gen1 = $import $_gen1 */ + ctx.rule = rules.get(1); tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_type_e(ctx); + subtree = parse_import(ctx); tree.add(subtree); - return tree; - } - return tree; - } - public ParseTree parse_outputs(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { - ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_outputs(ctx); - } - private static ParseTree parse_outputs(ParserContext ctx) throws SyntaxError { - Terminal current = ctx.tokens.current(); - Terminal next; - ParseTree subtree; - int rule = (current != null) ? table[34][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(92, "outputs")); - ctx.nonterminal = "outputs"; - tree.setList(false); - if (current == null) { - throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "outputs", - nonterminal_first.get(92), - nonterminal_rules.get(92) - )); - } - if (rule == 55) { - /* $outputs = :output :lbrace $_gen16 :rbrace -> Outputs( attributes=$2 ) */ - ctx.rule = rules.get(55); - LinkedHashMap parameters = new LinkedHashMap(); - parameters.put("attributes", 2); - tree.setAstTransformation(new AstTransformNodeCreator("Outputs", parameters)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_OUTPUT); - tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LBRACE); - tree.add(next); - subtree = parse__gen16(ctx); + subtree = parse__gen1(ctx); tree.add(subtree); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RBRACE); - tree.add(next); return tree; } - throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "outputs", - current, - nonterminal_first.get(92), - rules.get(55) - )); + return tree; } - public ParseTree parse__gen0(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen6(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen0(ctx); + return parse__gen6(ctx); } - private static ParseTree parse__gen0(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen6(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[35][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(93, "_gen0")); - ctx.nonterminal = "_gen0"; + int rule = (current != null) ? table[40][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(96, "_gen6")); + ctx.nonterminal = "_gen6"; tree.setList(true); if ( current != null && - !nonterminal_first.get(93).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(93).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(96).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(96).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 0) { - /* $_gen0 = $import $_gen1 */ - ctx.rule = rules.get(0); + if (rule == 16) { + /* $_gen6 = $declaration $_gen6 */ + ctx.rule = rules.get(16); tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_import(ctx); + subtree = parse_declaration(ctx); tree.add(subtree); - subtree = parse__gen1(ctx); + subtree = parse__gen6(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse__gen10(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_import_namespace(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen10(ctx); + return parse_import_namespace(ctx); } - private static ParseTree parse__gen10(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_import_namespace(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[36][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(94, "_gen10")); - ctx.nonterminal = "_gen10"; - tree.setList(true); - if ( current != null && - !nonterminal_first.get(94).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(94).contains(terminal_map.get(current.getId())) ) { - return tree; - } + int rule = (current != null) ? table[41][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(97, "import_namespace")); + ctx.nonterminal = "import_namespace"; + tree.setList(false); if (current == null) { - return tree; + throw new SyntaxError(ctx.error_formatter.unexpectedEof( + "import_namespace", + nonterminal_first.get(97), + nonterminal_rules.get(97) + )); } - if (rule == 30) { - /* $_gen10 = $command_part $_gen10 */ - ctx.rule = rules.get(30); - tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_command_part(ctx); - tree.add(subtree); - subtree = parse__gen10(ctx); - tree.add(subtree); + if (rule == 14) { + /* $import_namespace = :as :identifier -> $1 */ + ctx.rule = rules.get(14); + tree.setAstTransformation(new AstTransformSubstitution(1)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_AS); + tree.add(next); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER); + tree.add(next); return tree; } - return tree; + throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( + "import_namespace", + current, + nonterminal_first.get(97), + rules.get(14) + )); } - public ParseTree parse__gen26(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen12(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen26(ctx); + return parse__gen12(ctx); } - private static ParseTree parse__gen26(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen12(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[37][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(95, "_gen26")); - ctx.nonterminal = "_gen26"; + int rule = (current != null) ? table[42][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(98, "_gen12")); + ctx.nonterminal = "_gen12"; tree.setList(true); if ( current != null && - !nonterminal_first.get(95).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(95).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(98).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(98).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 86) { - /* $_gen26 = $mapping $_gen27 */ - ctx.rule = rules.get(86); + if (rule == 37) { + /* $_gen12 = $cmd_param_kv $_gen12 */ + ctx.rule = rules.get(37); tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_mapping(ctx); + subtree = parse_cmd_param_kv(ctx); tree.add(subtree); - subtree = parse__gen27(ctx); + subtree = parse__gen12(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse_workflow(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_map_kv(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_workflow(ctx); + return parse_map_kv(ctx); } - private static ParseTree parse_workflow(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_map_kv(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[38][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(96, "workflow")); - ctx.nonterminal = "workflow"; + int rule = (current != null) ? table[43][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(99, "map_kv")); + ctx.nonterminal = "map_kv"; tree.setList(false); if (current == null) { throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "workflow", - nonterminal_first.get(96), - nonterminal_rules.get(96) + "map_kv", + nonterminal_first.get(99), + nonterminal_rules.get(99) )); } - if (rule == 70) { - /* $workflow = :workflow :identifier :lbrace $_gen20 :rbrace -> Workflow( name=$1, body=$3 ) */ - ctx.rule = rules.get(70); + if (rule == 65) { + /* $map_kv = $e :colon $e -> MapLiteralKv( key=$0, value=$2 ) */ + ctx.rule = rules.get(65); LinkedHashMap parameters = new LinkedHashMap(); - parameters.put("name", 1); - parameters.put("body", 3); - tree.setAstTransformation(new AstTransformNodeCreator("Workflow", parameters)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_WORKFLOW); - tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER); - tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LBRACE); - tree.add(next); - subtree = parse__gen20(ctx); + parameters.put("key", 0); + parameters.put("value", 2); + tree.setAstTransformation(new AstTransformNodeCreator("MapLiteralKv", parameters)); + subtree = parse_e(ctx); tree.add(subtree); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RBRACE); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_COLON); tree.add(next); + subtree = parse_e(ctx); + tree.add(subtree); return tree; } throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "workflow", + "map_kv", current, - nonterminal_first.get(96), - rules.get(70) + nonterminal_first.get(99), + rules.get(65) )); } - public ParseTree parse__gen11(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen7(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen11(ctx); + return parse__gen7(ctx); } - private static ParseTree parse__gen11(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen7(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[39][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(97, "_gen11")); - ctx.nonterminal = "_gen11"; + int rule = (current != null) ? table[44][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(100, "_gen7")); + ctx.nonterminal = "_gen7"; tree.setList(true); if ( current != null && - !nonterminal_first.get(97).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(97).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(100).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(100).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 36) { - /* $_gen11 = $cmd_param_kv $_gen12 */ - ctx.rule = rules.get(36); + if (rule == 19) { + /* $_gen7 = $sections $_gen8 */ + ctx.rule = rules.get(19); tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_cmd_param_kv(ctx); + subtree = parse_sections(ctx); tree.add(subtree); - subtree = parse__gen12(ctx); + subtree = parse__gen8(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse_postfix_quantifier(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen13(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_postfix_quantifier(ctx); + return parse__gen13(ctx); } - private static ParseTree parse_postfix_quantifier(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen13(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[40][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(98, "postfix_quantifier")); - ctx.nonterminal = "postfix_quantifier"; - tree.setList(false); - if (current == null) { - throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "postfix_quantifier", - nonterminal_first.get(98), - nonterminal_rules.get(98) - )); - } - if (rule == 48) { - /* $postfix_quantifier = :qmark */ - ctx.rule = rules.get(48); - tree.setAstTransformation(new AstTransformSubstitution(0)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_QMARK); - tree.add(next); + int rule = (current != null) ? table[45][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(101, "_gen13")); + ctx.nonterminal = "_gen13"; + tree.setList(true); + if ( current != null && + !nonterminal_first.get(101).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(101).contains(terminal_map.get(current.getId())) ) { return tree; } - else if (rule == 49) { - /* $postfix_quantifier = :plus */ - ctx.rule = rules.get(49); - tree.setAstTransformation(new AstTransformSubstitution(0)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_PLUS); - tree.add(next); + if (current == null) { return tree; } - else if (rule == 50) { - /* $postfix_quantifier = :asterisk */ - ctx.rule = rules.get(50); + if (rule == 42) { + /* $_gen13 = $output_kv $_gen14 */ + ctx.rule = rules.get(42); tree.setAstTransformation(new AstTransformSubstitution(0)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_ASTERISK); - tree.add(next); + subtree = parse_output_kv(ctx); + tree.add(subtree); + subtree = parse__gen14(ctx); + tree.add(subtree); return tree; } - throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "postfix_quantifier", - current, - nonterminal_first.get(98), - rules.get(50) - )); + return tree; } - public ParseTree parse_if_stmt(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen21(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_if_stmt(ctx); + return parse__gen21(ctx); } - private static ParseTree parse_if_stmt(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen21(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[41][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(99, "if_stmt")); - ctx.nonterminal = "if_stmt"; + int rule = (current != null) ? table[46][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(102, "_gen21")); + ctx.nonterminal = "_gen21"; tree.setList(false); + if ( current != null && + !nonterminal_first.get(102).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(102).contains(terminal_map.get(current.getId())) ) { + return tree; + } if (current == null) { - throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "if_stmt", - nonterminal_first.get(99), - nonterminal_rules.get(99) - )); + return tree; } - if (rule == 94) { - /* $if_stmt = :if :lparen $e :rparen :lbrace $_gen20 :rbrace -> If( expression=$2, body=$5 ) */ - ctx.rule = rules.get(94); - LinkedHashMap parameters = new LinkedHashMap(); - parameters.put("expression", 2); - parameters.put("body", 5); - tree.setAstTransformation(new AstTransformNodeCreator("If", parameters)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IF); - tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LPAREN); - tree.add(next); - subtree = parse_e(ctx); - tree.add(subtree); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RPAREN); - tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LBRACE); - tree.add(next); - subtree = parse__gen20(ctx); + if (rule == 77) { + /* $_gen21 = $alias */ + ctx.rule = rules.get(77); + tree.setAstTransformation(new AstTransformSubstitution(0)); + subtree = parse_alias(ctx); tree.add(subtree); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RBRACE); - tree.add(next); return tree; } - throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "if_stmt", - current, - nonterminal_first.get(99), - rules.get(94) - )); + return tree; } - public ParseTree parse_import_namespace(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen18(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_import_namespace(ctx); + return parse__gen18(ctx); } - private static ParseTree parse_import_namespace(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen18(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[42][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(100, "import_namespace")); - ctx.nonterminal = "import_namespace"; + int rule = (current != null) ? table[47][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(103, "_gen18")); + ctx.nonterminal = "_gen18"; tree.setList(false); + if ( current != null && + !nonterminal_first.get(103).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(103).contains(terminal_map.get(current.getId())) ) { + return tree; + } if (current == null) { - throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "import_namespace", - nonterminal_first.get(100), - nonterminal_rules.get(100) - )); + return tree; } - if (rule == 14) { - /* $import_namespace = :as :identifier -> $1 */ - ctx.rule = rules.get(14); - tree.setAstTransformation(new AstTransformSubstitution(1)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_AS); - tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER); - tree.add(next); + if (rule == 59) { + /* $_gen18 = $setter */ + ctx.rule = rules.get(59); + tree.setAstTransformation(new AstTransformSubstitution(0)); + subtree = parse_setter(ctx); + tree.add(subtree); return tree; } - throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "import_namespace", - current, - nonterminal_first.get(100), - rules.get(14) - )); + return tree; } - public ParseTree parse__gen21(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen25(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen21(ctx); + return parse__gen25(ctx); } - private static ParseTree parse__gen21(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen25(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[43][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(101, "_gen21")); - ctx.nonterminal = "_gen21"; + int rule = (current != null) ? table[48][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(104, "_gen25")); + ctx.nonterminal = "_gen25"; tree.setList(true); if ( current != null && - !nonterminal_first.get(101).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(101).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(104).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(104).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 67) { - /* $_gen21 = $wf_body_element $_gen21 */ - ctx.rule = rules.get(67); + if (rule == 87) { + /* $_gen25 = $mapping $_gen26 */ + ctx.rule = rules.get(87); tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_wf_body_element(ctx); + subtree = parse_mapping(ctx); tree.add(subtree); - subtree = parse__gen21(ctx); + subtree = parse__gen26(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse__gen2(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen22(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen2(ctx); + return parse__gen22(ctx); } - private static ParseTree parse__gen2(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen22(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[44][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(102, "_gen2")); - ctx.nonterminal = "_gen2"; - tree.setList(true); + int rule = (current != null) ? table[49][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(105, "_gen22")); + ctx.nonterminal = "_gen22"; + tree.setList(false); if ( current != null && - !nonterminal_first.get(102).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(102).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(105).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(105).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 4) { - /* $_gen2 = $workflow_or_task $_gen3 */ - ctx.rule = rules.get(4); + if (rule == 79) { + /* $_gen22 = $call_body */ + ctx.rule = rules.get(79); tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_workflow_or_task(ctx); - tree.add(subtree); - subtree = parse__gen3(ctx); + subtree = parse_call_body(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse_sections(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_map(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_sections(ctx); + return parse_map(ctx); } - private static ParseTree parse_sections(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_map(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[45][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(103, "sections")); - ctx.nonterminal = "sections"; + int rule = (current != null) ? table[50][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(106, "map")); + ctx.nonterminal = "map"; tree.setList(false); if (current == null) { throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "sections", - nonterminal_first.get(103), - nonterminal_rules.get(103) + "map", + nonterminal_first.get(106), + nonterminal_rules.get(106) )); } - if (rule == 24) { - /* $sections = $command */ - ctx.rule = rules.get(24); - tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_command(ctx); + if (rule == 55) { + /* $map = :lbrace $_gen15 :rbrace -> $1 */ + ctx.rule = rules.get(55); + tree.setAstTransformation(new AstTransformSubstitution(1)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LBRACE); + tree.add(next); + subtree = parse__gen15(ctx); tree.add(subtree); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RBRACE); + tree.add(next); return tree; } - else if (rule == 25) { - /* $sections = $outputs */ - ctx.rule = rules.get(25); - tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_outputs(ctx); + throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( + "map", + current, + nonterminal_first.get(106), + rules.get(55) + )); + } + public ParseTree parse_command(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); + return parse_command(ctx); + } + private static ParseTree parse_command(ParserContext ctx) throws SyntaxError { + Terminal current = ctx.tokens.current(); + Terminal next; + ParseTree subtree; + int rule = (current != null) ? table[51][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(107, "command")); + ctx.nonterminal = "command"; + tree.setList(false); + if (current == null) { + throw new SyntaxError(ctx.error_formatter.unexpectedEof( + "command", + nonterminal_first.get(107), + nonterminal_rules.get(107) + )); + } + if (rule == 33) { + /* $command = :raw_command :raw_cmd_start $_gen9 :raw_cmd_end -> RawCommand( parts=$2 ) */ + ctx.rule = rules.get(33); + LinkedHashMap parameters = new LinkedHashMap(); + parameters.put("parts", 2); + tree.setAstTransformation(new AstTransformNodeCreator("RawCommand", parameters)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RAW_COMMAND); + tree.add(next); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RAW_CMD_START); + tree.add(next); + subtree = parse__gen9(ctx); tree.add(subtree); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RAW_CMD_END); + tree.add(next); return tree; } - else if (rule == 26) { - /* $sections = $runtime */ - ctx.rule = rules.get(26); - tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_runtime(ctx); - tree.add(subtree); + throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( + "command", + current, + nonterminal_first.get(107), + rules.get(33) + )); + } + public ParseTree parse__gen8(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); + return parse__gen8(ctx); + } + private static ParseTree parse__gen8(ParserContext ctx) throws SyntaxError { + Terminal current = ctx.tokens.current(); + Terminal next; + ParseTree subtree; + int rule = (current != null) ? table[52][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(108, "_gen8")); + ctx.nonterminal = "_gen8"; + tree.setList(true); + if ( current != null && + !nonterminal_first.get(108).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(108).contains(terminal_map.get(current.getId())) ) { return tree; } - else if (rule == 27) { - /* $sections = $parameter_meta */ - ctx.rule = rules.get(27); - tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_parameter_meta(ctx); - tree.add(subtree); + if (current == null) { return tree; } - else if (rule == 28) { - /* $sections = $meta */ - ctx.rule = rules.get(28); + if (rule == 20) { + /* $_gen8 = $sections $_gen8 */ + ctx.rule = rules.get(20); tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_meta(ctx); + subtree = parse_sections(ctx); + tree.add(subtree); + subtree = parse__gen8(ctx); tree.add(subtree); return tree; } - throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "sections", - current, - nonterminal_first.get(103), - rules.get(28) - )); + return tree; } - public ParseTree parse_alias(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_scatter(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_alias(ctx); + return parse_scatter(ctx); } - private static ParseTree parse_alias(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_scatter(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[46][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(104, "alias")); - ctx.nonterminal = "alias"; + int rule = (current != null) ? table[53][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(109, "scatter")); + ctx.nonterminal = "scatter"; tree.setList(false); if (current == null) { throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "alias", - nonterminal_first.get(104), - nonterminal_rules.get(104) + "scatter", + nonterminal_first.get(109), + nonterminal_rules.get(109) )); } - if (rule == 92) { - /* $alias = :as :identifier -> $1 */ - ctx.rule = rules.get(92); - tree.setAstTransformation(new AstTransformSubstitution(1)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_AS); + if (rule == 105) { + /* $scatter = :scatter :lparen :identifier :in $e :rparen :lbrace $_gen19 :rbrace -> Scatter( item=$2, collection=$4, body=$7 ) */ + ctx.rule = rules.get(105); + LinkedHashMap parameters = new LinkedHashMap(); + parameters.put("item", 2); + parameters.put("collection", 4); + parameters.put("body", 7); + tree.setAstTransformation(new AstTransformNodeCreator("Scatter", parameters)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_SCATTER); + tree.add(next); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LPAREN); tree.add(next); next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER); tree.add(next); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IN); + tree.add(next); + subtree = parse_e(ctx); + tree.add(subtree); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RPAREN); + tree.add(next); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LBRACE); + tree.add(next); + subtree = parse__gen19(ctx); + tree.add(subtree); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RBRACE); + tree.add(next); return tree; } throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "alias", + "scatter", current, - nonterminal_first.get(104), - rules.get(92) + nonterminal_first.get(109), + rules.get(105) )); } public ParseTree parse_mapping(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { @@ -4628,20 +5073,20 @@ private static ParseTree parse_mapping(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[47][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(105, "mapping")); + int rule = (current != null) ? table[54][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(110, "mapping")); ctx.nonterminal = "mapping"; tree.setList(false); if (current == null) { throw new SyntaxError(ctx.error_formatter.unexpectedEof( "mapping", - nonterminal_first.get(105), - nonterminal_rules.get(105) + nonterminal_first.get(110), + nonterminal_rules.get(110) )); } - if (rule == 91) { + if (rule == 92) { /* $mapping = :identifier :equal $e -> IOMapping( key=$0, value=$2 ) */ - ctx.rule = rules.get(91); + ctx.rule = rules.get(92); LinkedHashMap parameters = new LinkedHashMap(); parameters.put("key", 0); parameters.put("value", 2); @@ -4657,697 +5102,714 @@ private static ParseTree parse_mapping(ParserContext ctx) throws SyntaxError { throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( "mapping", current, - nonterminal_first.get(105), - rules.get(91) + nonterminal_first.get(110), + rules.get(92) )); } - public ParseTree parse__gen30(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen37(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen30(ctx); + return parse__gen37(ctx); } - private static ParseTree parse__gen30(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen37(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[48][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(106, "_gen30")); - ctx.nonterminal = "_gen30"; + int rule = (current != null) ? table[55][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(111, "_gen37")); + ctx.nonterminal = "_gen37"; tree.setList(true); if ( current != null && - !nonterminal_first.get(106).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(106).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(111).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(111).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 102) { - /* $_gen30 = :comma $type_e $_gen30 */ - ctx.rule = rules.get(102); + if (rule == 143) { + /* $_gen37 = :comma $map_kv $_gen37 */ + ctx.rule = rules.get(143); tree.setAstTransformation(new AstTransformSubstitution(0)); next = expect(ctx, WdlTerminalIdentifier.TERMINAL_COMMA); tree.add(next); tree.setListSeparator(next); - subtree = parse_type_e(ctx); + subtree = parse_map_kv(ctx); tree.add(subtree); - subtree = parse__gen30(ctx); + subtree = parse__gen37(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse__gen20(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen11(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen20(ctx); + return parse__gen11(ctx); } - private static ParseTree parse__gen20(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen11(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[49][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(107, "_gen20")); - ctx.nonterminal = "_gen20"; + int rule = (current != null) ? table[56][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(112, "_gen11")); + ctx.nonterminal = "_gen11"; tree.setList(true); if ( current != null && - !nonterminal_first.get(107).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(107).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(112).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(112).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 66) { - /* $_gen20 = $wf_body_element $_gen21 */ - ctx.rule = rules.get(66); + if (rule == 36) { + /* $_gen11 = $cmd_param_kv $_gen12 */ + ctx.rule = rules.get(36); tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_wf_body_element(ctx); + subtree = parse_cmd_param_kv(ctx); tree.add(subtree); - subtree = parse__gen21(ctx); + subtree = parse__gen12(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse__gen7(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen2(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen7(ctx); + return parse__gen2(ctx); } - private static ParseTree parse__gen7(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen2(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[50][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(108, "_gen7")); - ctx.nonterminal = "_gen7"; + int rule = (current != null) ? table[57][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(113, "_gen2")); + ctx.nonterminal = "_gen2"; tree.setList(true); if ( current != null && - !nonterminal_first.get(108).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(108).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(113).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(113).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 19) { - /* $_gen7 = $sections $_gen8 */ - ctx.rule = rules.get(19); + if (rule == 4) { + /* $_gen2 = $workflow_or_task $_gen3 */ + ctx.rule = rules.get(4); tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_sections(ctx); + subtree = parse_workflow_or_task(ctx); tree.add(subtree); - subtree = parse__gen8(ctx); + subtree = parse__gen3(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse_import(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen34(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_import(ctx); + return parse__gen34(ctx); } - private static ParseTree parse_import(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen34(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[51][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(109, "import")); - ctx.nonterminal = "import"; - tree.setList(false); + int rule = (current != null) ? table[58][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(114, "_gen34")); + ctx.nonterminal = "_gen34"; + tree.setList(true); + if ( current != null && + !nonterminal_first.get(114).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(114).contains(terminal_map.get(current.getId())) ) { + return tree; + } if (current == null) { - throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "import", - nonterminal_first.get(109), - nonterminal_rules.get(109) - )); + return tree; } - if (rule == 13) { - /* $import = :import :string $_gen4 -> Import( uri=$1, namespace=$2 ) */ - ctx.rule = rules.get(13); - LinkedHashMap parameters = new LinkedHashMap(); - parameters.put("uri", 1); - parameters.put("namespace", 2); - tree.setAstTransformation(new AstTransformNodeCreator("Import", parameters)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IMPORT); - tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_STRING); - tree.add(next); - subtree = parse__gen4(ctx); + if (rule == 136) { + /* $_gen34 = $object_kv $_gen35 */ + ctx.rule = rules.get(136); + tree.setAstTransformation(new AstTransformSubstitution(0)); + subtree = parse_object_kv(ctx); + tree.add(subtree); + subtree = parse__gen35(ctx); tree.add(subtree); return tree; } - throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "import", - current, - nonterminal_first.get(109), - rules.get(13) - )); + return tree; } - public ParseTree parse_object_kv(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_output_kv(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_object_kv(ctx); + return parse_output_kv(ctx); } - private static ParseTree parse_object_kv(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_output_kv(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[52][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(110, "object_kv")); - ctx.nonterminal = "object_kv"; + int rule = (current != null) ? table[59][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(115, "output_kv")); + ctx.nonterminal = "output_kv"; tree.setList(false); if (current == null) { throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "object_kv", - nonterminal_first.get(110), - nonterminal_rules.get(110) + "output_kv", + nonterminal_first.get(115), + nonterminal_rules.get(115) )); } - if (rule == 100) { - /* $object_kv = :identifier :colon $e -> ObjectKV( key=$0, value=$2 ) */ - ctx.rule = rules.get(100); + if (rule == 47) { + /* $output_kv = $type_e :identifier :equal $e -> Output( type=$0, var=$1, expression=$3 ) */ + ctx.rule = rules.get(47); LinkedHashMap parameters = new LinkedHashMap(); - parameters.put("key", 0); - parameters.put("value", 2); - tree.setAstTransformation(new AstTransformNodeCreator("ObjectKV", parameters)); + parameters.put("type", 0); + parameters.put("var", 1); + parameters.put("expression", 3); + tree.setAstTransformation(new AstTransformNodeCreator("Output", parameters)); + subtree = parse_type_e(ctx); + tree.add(subtree); next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER); tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_COLON); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_EQUAL); tree.add(next); subtree = parse_e(ctx); tree.add(subtree); return tree; } throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "object_kv", + "output_kv", current, - nonterminal_first.get(110), - rules.get(100) + nonterminal_first.get(115), + rules.get(47) )); } - public ParseTree parse__gen8(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen27(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen8(ctx); + return parse__gen27(ctx); } - private static ParseTree parse__gen8(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen27(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[53][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(111, "_gen8")); - ctx.nonterminal = "_gen8"; + int rule = (current != null) ? table[60][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(116, "_gen27")); + ctx.nonterminal = "_gen27"; tree.setList(true); if ( current != null && - !nonterminal_first.get(111).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(111).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(116).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(116).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 20) { - /* $_gen8 = $sections $_gen8 */ - ctx.rule = rules.get(20); + if (rule == 94) { + /* $_gen27 = $wf_output $_gen28 */ + ctx.rule = rules.get(94); tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_sections(ctx); + subtree = parse_wf_output(ctx); tree.add(subtree); - subtree = parse__gen8(ctx); + subtree = parse__gen28(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse__gen32(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen17(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen32(ctx); + return parse__gen17(ctx); } - private static ParseTree parse__gen32(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen17(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[54][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(112, "_gen32")); - ctx.nonterminal = "_gen32"; - tree.setList(true); + int rule = (current != null) ? table[61][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(117, "_gen17")); + ctx.nonterminal = "_gen17"; + tree.setList(false); if ( current != null && - !nonterminal_first.get(112).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(112).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(117).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(117).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 124) { - /* $_gen32 = :comma $e $_gen32 */ - ctx.rule = rules.get(124); + if (rule == 57) { + /* $_gen17 = $postfix_quantifier */ + ctx.rule = rules.get(57); tree.setAstTransformation(new AstTransformSubstitution(0)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_COMMA); - tree.add(next); - tree.setListSeparator(next); - subtree = parse_e(ctx); - tree.add(subtree); - subtree = parse__gen32(ctx); + subtree = parse_postfix_quantifier(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse__gen13(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_wf_output_wildcard(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen13(ctx); + return parse_wf_output_wildcard(ctx); } - private static ParseTree parse__gen13(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_wf_output_wildcard(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[56][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(114, "_gen13")); - ctx.nonterminal = "_gen13"; + int rule = (current != null) ? table[62][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(118, "wf_output_wildcard")); + ctx.nonterminal = "wf_output_wildcard"; tree.setList(false); - if ( current != null && - !nonterminal_first.get(114).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(114).contains(terminal_map.get(current.getId())) ) { - return tree; - } if (current == null) { - return tree; + throw new SyntaxError(ctx.error_formatter.unexpectedEof( + "wf_output_wildcard", + nonterminal_first.get(118), + nonterminal_rules.get(118) + )); } - if (rule == 40) { - /* $_gen13 = :string */ - ctx.rule = rules.get(40); - tree.setAstTransformation(new AstTransformSubstitution(0)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_STRING); + if (rule == 102) { + /* $wf_output_wildcard = :dot :asterisk -> $1 */ + ctx.rule = rules.get(102); + tree.setAstTransformation(new AstTransformSubstitution(1)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_DOT); + tree.add(next); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_ASTERISK); tree.add(next); return tree; } - return tree; + throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( + "wf_output_wildcard", + current, + nonterminal_first.get(118), + rules.get(102) + )); } - public ParseTree parse_scatter(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen19(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_scatter(ctx); + return parse__gen19(ctx); } - private static ParseTree parse_scatter(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen19(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[57][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(115, "scatter")); - ctx.nonterminal = "scatter"; - tree.setList(false); + int rule = (current != null) ? table[63][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(119, "_gen19")); + ctx.nonterminal = "_gen19"; + tree.setList(true); + if ( current != null && + !nonterminal_first.get(119).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(119).contains(terminal_map.get(current.getId())) ) { + return tree; + } if (current == null) { - throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "scatter", - nonterminal_first.get(115), - nonterminal_rules.get(115) - )); + return tree; } - if (rule == 95) { - /* $scatter = :scatter :lparen :identifier :in $e :rparen :lbrace $_gen20 :rbrace -> Scatter( item=$2, collection=$4, body=$7 ) */ - ctx.rule = rules.get(95); - LinkedHashMap parameters = new LinkedHashMap(); - parameters.put("item", 2); - parameters.put("collection", 4); - parameters.put("body", 7); - tree.setAstTransformation(new AstTransformNodeCreator("Scatter", parameters)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_SCATTER); - tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LPAREN); - tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER); - tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IN); - tree.add(next); - subtree = parse_e(ctx); + if (rule == 66) { + /* $_gen19 = $wf_body_element $_gen20 */ + ctx.rule = rules.get(66); + tree.setAstTransformation(new AstTransformSubstitution(0)); + subtree = parse_wf_body_element(ctx); tree.add(subtree); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RPAREN); - tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LBRACE); - tree.add(next); subtree = parse__gen20(ctx); tree.add(subtree); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RBRACE); - tree.add(next); return tree; } - throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "scatter", - current, - nonterminal_first.get(115), - rules.get(95) - )); + return tree; } - public ParseTree parse_call_body(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_sections(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_call_body(ctx); + return parse_sections(ctx); } - private static ParseTree parse_call_body(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_sections(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[58][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(116, "call_body")); - ctx.nonterminal = "call_body"; + int rule = (current != null) ? table[64][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(120, "sections")); + ctx.nonterminal = "sections"; tree.setList(false); if (current == null) { throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "call_body", - nonterminal_first.get(116), - nonterminal_rules.get(116) + "sections", + nonterminal_first.get(120), + nonterminal_rules.get(120) )); } - if (rule == 85) { - /* $call_body = :lbrace $_gen5 $_gen24 :rbrace -> CallBody( declarations=$1, io=$2 ) */ - ctx.rule = rules.get(85); - LinkedHashMap parameters = new LinkedHashMap(); - parameters.put("declarations", 1); - parameters.put("io", 2); - tree.setAstTransformation(new AstTransformNodeCreator("CallBody", parameters)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LBRACE); - tree.add(next); - subtree = parse__gen5(ctx); + if (rule == 24) { + /* $sections = $command */ + ctx.rule = rules.get(24); + tree.setAstTransformation(new AstTransformSubstitution(0)); + subtree = parse_command(ctx); + tree.add(subtree); + return tree; + } + else if (rule == 25) { + /* $sections = $outputs */ + ctx.rule = rules.get(25); + tree.setAstTransformation(new AstTransformSubstitution(0)); + subtree = parse_outputs(ctx); + tree.add(subtree); + return tree; + } + else if (rule == 26) { + /* $sections = $runtime */ + ctx.rule = rules.get(26); + tree.setAstTransformation(new AstTransformSubstitution(0)); + subtree = parse_runtime(ctx); + tree.add(subtree); + return tree; + } + else if (rule == 27) { + /* $sections = $parameter_meta */ + ctx.rule = rules.get(27); + tree.setAstTransformation(new AstTransformSubstitution(0)); + subtree = parse_parameter_meta(ctx); tree.add(subtree); - subtree = parse__gen24(ctx); + return tree; + } + else if (rule == 28) { + /* $sections = $meta */ + ctx.rule = rules.get(28); + tree.setAstTransformation(new AstTransformSubstitution(0)); + subtree = parse_meta(ctx); tree.add(subtree); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RBRACE); - tree.add(next); return tree; } throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "call_body", + "sections", current, - nonterminal_first.get(116), - rules.get(85) + nonterminal_first.get(120), + rules.get(28) )); } - public ParseTree parse__gen9(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen14(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen9(ctx); + return parse__gen14(ctx); } - private static ParseTree parse__gen9(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen14(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[59][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(117, "_gen9")); - ctx.nonterminal = "_gen9"; + int rule = (current != null) ? table[65][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(121, "_gen14")); + ctx.nonterminal = "_gen14"; tree.setList(true); if ( current != null && - !nonterminal_first.get(117).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(117).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(121).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(121).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 29) { - /* $_gen9 = $command_part $_gen10 */ - ctx.rule = rules.get(29); + if (rule == 43) { + /* $_gen14 = $output_kv $_gen14 */ + ctx.rule = rules.get(43); tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_command_part(ctx); + subtree = parse_output_kv(ctx); tree.add(subtree); - subtree = parse__gen10(ctx); + subtree = parse__gen14(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse_document(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen30(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_document(ctx); + return parse__gen30(ctx); } - private static ParseTree parse_document(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen30(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[60][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(118, "document")); - ctx.nonterminal = "document"; - tree.setList(false); + int rule = (current != null) ? table[66][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(122, "_gen30")); + ctx.nonterminal = "_gen30"; + tree.setList(true); if ( current != null && - !nonterminal_first.get(118).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(118).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(122).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(122).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 8) { - /* $document = $_gen0 $_gen2 -> Document( imports=$0, definitions=$1 ) */ - ctx.rule = rules.get(8); - LinkedHashMap parameters = new LinkedHashMap(); - parameters.put("imports", 0); - parameters.put("definitions", 1); - tree.setAstTransformation(new AstTransformNodeCreator("Document", parameters)); - subtree = parse__gen0(ctx); + if (rule == 107) { + /* $_gen30 = $type_e $_gen31 */ + ctx.rule = rules.get(107); + tree.setAstTransformation(new AstTransformSubstitution(0)); + subtree = parse_type_e(ctx); tree.add(subtree); - subtree = parse__gen2(ctx); + subtree = parse__gen31(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse__gen33(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_setter(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen33(ctx); + return parse_setter(ctx); } - private static ParseTree parse__gen33(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_setter(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[61][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(119, "_gen33")); - ctx.nonterminal = "_gen33"; - tree.setList(true); - if ( current != null && - !nonterminal_first.get(119).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(119).contains(terminal_map.get(current.getId())) ) { - return tree; - } + int rule = (current != null) ? table[67][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(123, "setter")); + ctx.nonterminal = "setter"; + tree.setList(false); if (current == null) { - return tree; + throw new SyntaxError(ctx.error_formatter.unexpectedEof( + "setter", + nonterminal_first.get(123), + nonterminal_rules.get(123) + )); } - if (rule == 130) { - /* $_gen33 = $object_kv $_gen34 */ - ctx.rule = rules.get(130); - tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_object_kv(ctx); - tree.add(subtree); - subtree = parse__gen34(ctx); + if (rule == 62) { + /* $setter = :equal $e -> $1 */ + ctx.rule = rules.get(62); + tree.setAstTransformation(new AstTransformSubstitution(1)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_EQUAL); + tree.add(next); + subtree = parse_e(ctx); tree.add(subtree); return tree; } - return tree; + throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( + "setter", + current, + nonterminal_first.get(123), + rules.get(62) + )); } - public ParseTree parse_command(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_declaration(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_command(ctx); + return parse_declaration(ctx); } - private static ParseTree parse_command(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_declaration(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[62][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(120, "command")); - ctx.nonterminal = "command"; + int rule = (current != null) ? table[68][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(124, "declaration")); + ctx.nonterminal = "declaration"; tree.setList(false); if (current == null) { throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "command", - nonterminal_first.get(120), - nonterminal_rules.get(120) + "declaration", + nonterminal_first.get(124), + nonterminal_rules.get(124) )); } - if (rule == 33) { - /* $command = :raw_command :raw_cmd_start $_gen9 :raw_cmd_end -> RawCommand( parts=$2 ) */ - ctx.rule = rules.get(33); + if (rule == 61) { + /* $declaration = $type_e $_gen17 :identifier $_gen18 -> Declaration( type=$0, postfix=$1, name=$2, expression=$3 ) */ + ctx.rule = rules.get(61); LinkedHashMap parameters = new LinkedHashMap(); - parameters.put("parts", 2); - tree.setAstTransformation(new AstTransformNodeCreator("RawCommand", parameters)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RAW_COMMAND); - tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RAW_CMD_START); - tree.add(next); - subtree = parse__gen9(ctx); + parameters.put("type", 0); + parameters.put("postfix", 1); + parameters.put("name", 2); + parameters.put("expression", 3); + tree.setAstTransformation(new AstTransformNodeCreator("Declaration", parameters)); + subtree = parse_type_e(ctx); tree.add(subtree); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RAW_CMD_END); + subtree = parse__gen17(ctx); + tree.add(subtree); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER); tree.add(next); + subtree = parse__gen18(ctx); + tree.add(subtree); return tree; } throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "command", + "declaration", current, - nonterminal_first.get(120), - rules.get(33) + nonterminal_first.get(124), + rules.get(61) )); } - public ParseTree parse__gen6(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_if_stmt(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen6(ctx); + return parse_if_stmt(ctx); } - private static ParseTree parse__gen6(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_if_stmt(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[63][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(121, "_gen6")); - ctx.nonterminal = "_gen6"; - tree.setList(true); - if ( current != null && - !nonterminal_first.get(121).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(121).contains(terminal_map.get(current.getId())) ) { - return tree; - } + int rule = (current != null) ? table[69][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(125, "if_stmt")); + ctx.nonterminal = "if_stmt"; + tree.setList(false); if (current == null) { - return tree; + throw new SyntaxError(ctx.error_formatter.unexpectedEof( + "if_stmt", + nonterminal_first.get(125), + nonterminal_rules.get(125) + )); } - if (rule == 16) { - /* $_gen6 = $declaration $_gen6 */ - ctx.rule = rules.get(16); - tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_declaration(ctx); + if (rule == 104) { + /* $if_stmt = :if :lparen $e :rparen :lbrace $_gen19 :rbrace -> If( expression=$2, body=$5 ) */ + ctx.rule = rules.get(104); + LinkedHashMap parameters = new LinkedHashMap(); + parameters.put("expression", 2); + parameters.put("body", 5); + tree.setAstTransformation(new AstTransformNodeCreator("If", parameters)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IF); + tree.add(next); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LPAREN); + tree.add(next); + subtree = parse_e(ctx); tree.add(subtree); - subtree = parse__gen6(ctx); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RPAREN); + tree.add(next); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_LBRACE); + tree.add(next); + subtree = parse__gen19(ctx); tree.add(subtree); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_RBRACE); + tree.add(next); return tree; } - return tree; + throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( + "if_stmt", + current, + nonterminal_first.get(125), + rules.get(104) + )); } - public ParseTree parse__gen27(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen24(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen27(ctx); + return parse__gen24(ctx); } - private static ParseTree parse__gen27(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen24(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[64][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(122, "_gen27")); - ctx.nonterminal = "_gen27"; + int rule = (current != null) ? table[70][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(126, "_gen24")); + ctx.nonterminal = "_gen24"; tree.setList(true); if ( current != null && - !nonterminal_first.get(122).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(122).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(126).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(126).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 87) { - /* $_gen27 = :comma $mapping $_gen27 */ - ctx.rule = rules.get(87); + if (rule == 83) { + /* $_gen24 = $call_input $_gen24 */ + ctx.rule = rules.get(83); tree.setAstTransformation(new AstTransformSubstitution(0)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_COMMA); - tree.add(next); - tree.setListSeparator(next); - subtree = parse_mapping(ctx); + subtree = parse_call_input(ctx); tree.add(subtree); - subtree = parse__gen27(ctx); + subtree = parse__gen24(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse__gen17(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse_meta(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen17(ctx); + return parse_meta(ctx); } - private static ParseTree parse__gen17(ParserContext ctx) throws SyntaxError { + private static ParseTree parse_meta(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[65][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(123, "_gen17")); - ctx.nonterminal = "_gen17"; - tree.setList(true); - if ( current != null && - !nonterminal_first.get(123).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(123).contains(terminal_map.get(current.getId())) ) { - return tree; - } + int rule = (current != null) ? table[71][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(127, "meta")); + ctx.nonterminal = "meta"; + tree.setList(false); if (current == null) { - return tree; + throw new SyntaxError(ctx.error_formatter.unexpectedEof( + "meta", + nonterminal_first.get(127), + nonterminal_rules.get(127) + )); } - if (rule == 52) { - /* $_gen17 = $output_kv $_gen17 */ - ctx.rule = rules.get(52); - tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_output_kv(ctx); - tree.add(subtree); - subtree = parse__gen17(ctx); + if (rule == 50) { + /* $meta = :meta $map -> Meta( map=$1 ) */ + ctx.rule = rules.get(50); + LinkedHashMap parameters = new LinkedHashMap(); + parameters.put("map", 1); + tree.setAstTransformation(new AstTransformNodeCreator("Meta", parameters)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_META); + tree.add(next); + subtree = parse_map(ctx); tree.add(subtree); return tree; } - return tree; + throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( + "meta", + current, + nonterminal_first.get(127), + rules.get(50) + )); } - public ParseTree parse__gen28(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen35(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse__gen28(ctx); + return parse__gen35(ctx); } - private static ParseTree parse__gen28(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen35(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[66][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(124, "_gen28")); - ctx.nonterminal = "_gen28"; - tree.setList(false); + int rule = (current != null) ? table[72][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(128, "_gen35")); + ctx.nonterminal = "_gen35"; + tree.setList(true); if ( current != null && - !nonterminal_first.get(124).contains(terminal_map.get(current.getId())) && - nonterminal_follow.get(124).contains(terminal_map.get(current.getId())) ) { + !nonterminal_first.get(128).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(128).contains(terminal_map.get(current.getId())) ) { return tree; } if (current == null) { return tree; } - if (rule == 96) { - /* $_gen28 = $setter */ - ctx.rule = rules.get(96); + if (rule == 137) { + /* $_gen35 = :comma $object_kv $_gen35 */ + ctx.rule = rules.get(137); tree.setAstTransformation(new AstTransformSubstitution(0)); - subtree = parse_setter(ctx); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_COMMA); + tree.add(next); + tree.setListSeparator(next); + subtree = parse_object_kv(ctx); + tree.add(subtree); + subtree = parse__gen35(ctx); tree.add(subtree); return tree; } return tree; } - public ParseTree parse_cmd_param_kv(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { + public ParseTree parse__gen33(List tokens, SyntaxErrorFormatter error_formatter) throws SyntaxError { ParserContext ctx = new ParserContext(new TokenStream(tokens), error_formatter); - return parse_cmd_param_kv(ctx); + return parse__gen33(ctx); } - private static ParseTree parse_cmd_param_kv(ParserContext ctx) throws SyntaxError { + private static ParseTree parse__gen33(ParserContext ctx) throws SyntaxError { Terminal current = ctx.tokens.current(); Terminal next; ParseTree subtree; - int rule = (current != null) ? table[67][current.getId()] : -1; - ParseTree tree = new ParseTree( new NonTerminal(125, "cmd_param_kv")); - ctx.nonterminal = "cmd_param_kv"; - tree.setList(false); + int rule = (current != null) ? table[74][current.getId()] : -1; + ParseTree tree = new ParseTree( new NonTerminal(130, "_gen33")); + ctx.nonterminal = "_gen33"; + tree.setList(true); + if ( current != null && + !nonterminal_first.get(130).contains(terminal_map.get(current.getId())) && + nonterminal_follow.get(130).contains(terminal_map.get(current.getId())) ) { + return tree; + } if (current == null) { - throw new SyntaxError(ctx.error_formatter.unexpectedEof( - "cmd_param_kv", - nonterminal_first.get(125), - nonterminal_rules.get(125) - )); + return tree; } - if (rule == 47) { - /* $cmd_param_kv = :cmd_attr_hint :identifier :equal $e -> CommandParameterAttr( key=$1, value=$3 ) */ - ctx.rule = rules.get(47); - LinkedHashMap parameters = new LinkedHashMap(); - parameters.put("key", 1); - parameters.put("value", 3); - tree.setAstTransformation(new AstTransformNodeCreator("CommandParameterAttr", parameters)); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_CMD_ATTR_HINT); - tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_IDENTIFIER); - tree.add(next); - next = expect(ctx, WdlTerminalIdentifier.TERMINAL_EQUAL); + if (rule == 130) { + /* $_gen33 = :comma $e $_gen33 */ + ctx.rule = rules.get(130); + tree.setAstTransformation(new AstTransformSubstitution(0)); + next = expect(ctx, WdlTerminalIdentifier.TERMINAL_COMMA); tree.add(next); + tree.setListSeparator(next); subtree = parse_e(ctx); tree.add(subtree); + subtree = parse__gen33(ctx); + tree.add(subtree); return tree; } - throw new SyntaxError(ctx.error_formatter.unexpectedSymbol( - "cmd_param_kv", - current, - nonterminal_first.get(125), - rules.get(47) - )); + return tree; } /* Section: Lexer */ private Map> regex = null; @@ -5453,10 +5915,28 @@ public void default_action(LexerContext lctx, TerminalIdentifier terminal, Strin emit(lctx, terminal, source_string, line, col); } /* START USER CODE */ - /* END USER CODE */ - public Object init() { - return null; + private class WdlContext { + public String wf_or_task = null; +} +public Object init() { + return new WdlContext(); +} +public void workflow(LexerContext ctx, TerminalIdentifier terminal, String source_string, int line, int col) { + ((WdlContext) ctx.context).wf_or_task = "workflow"; + default_action(ctx, terminal, source_string, line, col); +} +public void task(LexerContext ctx, TerminalIdentifier terminal, String source_string, int line, int col) { + ((WdlContext) ctx.context).wf_or_task = "task"; + default_action(ctx, terminal, source_string, line, col); +} +public void output(LexerContext ctx, TerminalIdentifier terminal, String source_string, int line, int col) { + WdlContext user_ctx = (WdlContext) ctx.context; + if (user_ctx.wf_or_task != null && user_ctx.wf_or_task.equals("workflow")) { + ctx.stack.push("wf_output"); } + default_action(ctx, terminal, source_string, line, col); +} + /* END USER CODE */ public void destroy(Object context) { return; } @@ -5478,247 +5958,535 @@ private void lexer_init() throws SyntaxError { this.regex = new HashMap>(); this.regex.put("default", Arrays.asList(new HermesRegex[] { new HermesRegex( - Pattern.compile("\\s+"), + Pattern.compile("\\s+"), + Arrays.asList(new LexerOutput[] { + }) + ), + new HermesRegex( + Pattern.compile("/\\*(.*?)\\*/", Pattern.DOTALL), + Arrays.asList(new LexerOutput[] { + }) + ), + new HermesRegex( + Pattern.compile("#.*"), + Arrays.asList(new LexerOutput[] { + }) + ), + new HermesRegex( + Pattern.compile("task(?![a-zA-Z0-9_])"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_TASK, + 0, + getFunction("task") + ), + }) + ), + new HermesRegex( + Pattern.compile("(call)\\s+"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_CALL, + 1, + getFunction("default_action") + ), + new LexerStackPush("task_fqn"), + }) + ), + new HermesRegex( + Pattern.compile("workflow(?![a-zA-Z0-9_])"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_WORKFLOW, + 0, + getFunction("workflow") + ), + }) + ), + new HermesRegex( + Pattern.compile("import(?![a-zA-Z0-9_])"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_IMPORT, + 0, + getFunction("default_action") + ), + }) + ), + new HermesRegex( + Pattern.compile("input(?![a-zA-Z0-9_])"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_INPUT, + 0, + getFunction("default_action") + ), + }) + ), + new HermesRegex( + Pattern.compile("output(?![a-zA-Z0-9_])"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_OUTPUT, + 0, + getFunction("output") + ), + }) + ), + new HermesRegex( + Pattern.compile("as(?![a-zA-Z0-9_])"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_AS, + 0, + getFunction("default_action") + ), + }) + ), + new HermesRegex( + Pattern.compile("if(?![a-zA-Z0-9_])"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_IF, + 0, + getFunction("default_action") + ), + }) + ), + new HermesRegex( + Pattern.compile("while(?![a-zA-Z0-9_])"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_WHILE, + 0, + getFunction("default_action") + ), + }) + ), + new HermesRegex( + Pattern.compile("runtime(?![a-zA-Z0-9_])"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_RUNTIME, + 0, + getFunction("default_action") + ), + }) + ), + new HermesRegex( + Pattern.compile("scatter(?![a-zA-Z0-9_])"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_SCATTER, + 0, + getFunction("default_action") + ), + new LexerStackPush("scatter"), + }) + ), + new HermesRegex( + Pattern.compile("command\\s*(?=<<<)"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, + 0, + getFunction("default_action") + ), + new LexerStackPush("raw_command2"), + }) + ), + new HermesRegex( + Pattern.compile("command\\s*(?=\\{)"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, + 0, + getFunction("default_action") + ), + new LexerStackPush("raw_command"), + }) + ), + new HermesRegex( + Pattern.compile("parameter_meta(?![a-zA-Z0-9_])"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_PARAMETER_META, + 0, + getFunction("default_action") + ), + }) + ), + new HermesRegex( + Pattern.compile("meta(?![a-zA-Z0-9_])"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_META, + 0, + getFunction("default_action") + ), + }) + ), + new HermesRegex( + Pattern.compile("(true|false)(?![a-zA-Z0-9_])"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_BOOLEAN, + 0, + getFunction("default_action") + ), + }) + ), + new HermesRegex( + Pattern.compile("(object)\\s*(\\{)"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_OBJECT, + 0, + getFunction("default_action") + ), + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_LBRACE, + 0, + getFunction("default_action") + ), + }) + ), + new HermesRegex( + Pattern.compile("(Array|Map|Object|Boolean|Int|Float|Uri|File|String)(?![a-zA-Z0-9_])(?![a-zA-Z0-9_])"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_TYPE, + 0, + getFunction("default_action") + ), + }) + ), + new HermesRegex( + Pattern.compile("[a-zA-Z]([a-zA-Z0-9_])*"), Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + 0, + getFunction("default_action") + ), }) ), new HermesRegex( - Pattern.compile("/\\*(.*?)\\*/", Pattern.DOTALL), + Pattern.compile("\"([^\"]*)\""), Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_STRING, + 1, + getFunction("default_action") + ), }) ), new HermesRegex( - Pattern.compile("#.*"), + Pattern.compile("'([^']*)'"), Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_STRING, + 1, + getFunction("default_action") + ), }) ), new HermesRegex( - Pattern.compile("task(?![a-zA-Z0-9_])"), + Pattern.compile(":"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_TASK, + WdlTerminalIdentifier.TERMINAL_COLON, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("(call)\\s+"), + Pattern.compile(","), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_CALL, - 1, + WdlTerminalIdentifier.TERMINAL_COMMA, + 0, getFunction("default_action") ), - new LexerStackPush("task_fqn"), }) ), new HermesRegex( - Pattern.compile("workflow(?![a-zA-Z0-9_])"), + Pattern.compile("=="), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_WORKFLOW, + WdlTerminalIdentifier.TERMINAL_DOUBLE_EQUAL, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("import(?![a-zA-Z0-9_])"), + Pattern.compile("\\|\\|"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_IMPORT, + WdlTerminalIdentifier.TERMINAL_DOUBLE_PIPE, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("input(?![a-zA-Z0-9_])"), + Pattern.compile("\\&\\&"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_INPUT, + WdlTerminalIdentifier.TERMINAL_DOUBLE_AMPERSAND, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("output(?![a-zA-Z0-9_])"), + Pattern.compile("!="), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_OUTPUT, + WdlTerminalIdentifier.TERMINAL_NOT_EQUAL, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("as(?![a-zA-Z0-9_])"), + Pattern.compile("="), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_AS, + WdlTerminalIdentifier.TERMINAL_EQUAL, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("if(?![a-zA-Z0-9_])"), + Pattern.compile("\\."), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_IF, + WdlTerminalIdentifier.TERMINAL_DOT, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("while(?![a-zA-Z0-9_])"), + Pattern.compile("\\{"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_WHILE, + WdlTerminalIdentifier.TERMINAL_LBRACE, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("runtime(?![a-zA-Z0-9_])"), + Pattern.compile("\\}"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_RUNTIME, + WdlTerminalIdentifier.TERMINAL_RBRACE, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("scatter(?![a-zA-Z0-9_])"), + Pattern.compile("\\("), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_SCATTER, + WdlTerminalIdentifier.TERMINAL_LPAREN, 0, getFunction("default_action") ), - new LexerStackPush("scatter"), }) ), new HermesRegex( - Pattern.compile("command\\s*(?=<<<)"), + Pattern.compile("\\)"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, + WdlTerminalIdentifier.TERMINAL_RPAREN, 0, getFunction("default_action") ), - new LexerStackPush("raw_command2"), }) ), new HermesRegex( - Pattern.compile("command\\s*(?=\\{)"), + Pattern.compile("\\["), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_RAW_COMMAND, + WdlTerminalIdentifier.TERMINAL_LSQUARE, 0, getFunction("default_action") ), - new LexerStackPush("raw_command"), }) ), new HermesRegex( - Pattern.compile("parameter_meta(?![a-zA-Z0-9_])"), + Pattern.compile("\\]"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_PARAMETER_META, + WdlTerminalIdentifier.TERMINAL_RSQUARE, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("meta(?![a-zA-Z0-9_])"), + Pattern.compile("\\+"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_META, + WdlTerminalIdentifier.TERMINAL_PLUS, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("(true|false)(?![a-zA-Z0-9_])"), + Pattern.compile("\\*"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_BOOLEAN, + WdlTerminalIdentifier.TERMINAL_ASTERISK, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("(object)\\s*(\\{)"), + Pattern.compile("-"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_OBJECT, + WdlTerminalIdentifier.TERMINAL_DASH, 0, getFunction("default_action") ), + }) + ), + new HermesRegex( + Pattern.compile("/"), + Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_SLASH, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("(Array|Map|Object|Boolean|Int|Float|Uri|File|String)(?![a-zA-Z0-9_])(?![a-zA-Z0-9_])"), + Pattern.compile("%"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_TYPE, + WdlTerminalIdentifier.TERMINAL_PERCENT, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("[a-zA-Z]([a-zA-Z0-9_])*"), + Pattern.compile("<="), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_LTEQ, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("\"([^\"]*)\""), + Pattern.compile("<"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_STRING, - 1, + WdlTerminalIdentifier.TERMINAL_LT, + 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("'([^']*)'"), + Pattern.compile(">="), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_STRING, - 1, + WdlTerminalIdentifier.TERMINAL_GTEQ, + 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile(":"), + Pattern.compile(">"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_COLON, + WdlTerminalIdentifier.TERMINAL_GT, + 0, + getFunction("default_action") + ), + }) + ), + new HermesRegex( + Pattern.compile("!"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_NOT, + 0, + getFunction("default_action") + ), + }) + ), + new HermesRegex( + Pattern.compile("\\?"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_QMARK, + 0, + getFunction("default_action") + ), + }) + ), + new HermesRegex( + Pattern.compile("-?[0-9]+\\.[0-9]+"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_FLOAT, + 0, + getFunction("default_action") + ), + }) + ), + new HermesRegex( + Pattern.compile("[0-9]+"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_INTEGER, + 0, + getFunction("default_action") + ), + }) + ), + })); + this.regex.put("wf_output", Arrays.asList(new HermesRegex[] { + new HermesRegex( + Pattern.compile("\\s+"), + Arrays.asList(new LexerOutput[] { + }) + ), + new HermesRegex( + Pattern.compile("\\{"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_LBRACE, + 0, + getFunction("default_action") + ), + }) + ), + new HermesRegex( + Pattern.compile("\\}"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_RBRACE, 0, getFunction("default_action") ), + new LexerAction("pop"), }) ), new HermesRegex( @@ -5732,230 +6500,282 @@ private void lexer_init() throws SyntaxError { }) ), new HermesRegex( - Pattern.compile("=="), + Pattern.compile("\\."), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_DOUBLE_EQUAL, + WdlTerminalIdentifier.TERMINAL_DOT, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("\\|\\|"), + Pattern.compile("\\*"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_DOUBLE_PIPE, + WdlTerminalIdentifier.TERMINAL_ASTERISK, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("\\&\\&"), + Pattern.compile("[a-zA-Z]([a-zA-Z0-9_])*(\\.[a-zA-Z]([a-zA-Z0-9_])*)*"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_DOUBLE_AMPERSAND, + WdlTerminalIdentifier.TERMINAL_FQN, 0, getFunction("default_action") ), }) ), + })); + this.regex.put("task_fqn", Arrays.asList(new HermesRegex[] { new HermesRegex( - Pattern.compile("!="), + Pattern.compile("\\s+"), + Arrays.asList(new LexerOutput[] { + }) + ), + new HermesRegex( + Pattern.compile("[a-zA-Z]([a-zA-Z0-9_])*(\\.[a-zA-Z]([a-zA-Z0-9_])*)*"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_NOT_EQUAL, + WdlTerminalIdentifier.TERMINAL_FQN, 0, getFunction("default_action") ), + new LexerAction("pop"), + }) + ), + })); + this.regex.put("scatter", Arrays.asList(new HermesRegex[] { + new HermesRegex( + Pattern.compile("\\s+"), + Arrays.asList(new LexerOutput[] { }) ), new HermesRegex( - Pattern.compile("="), + Pattern.compile("\\)"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_EQUAL, + WdlTerminalIdentifier.TERMINAL_RPAREN, + 0, + getFunction("default_action") + ), + new LexerAction("pop"), + }) + ), + new HermesRegex( + Pattern.compile("\\("), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_LPAREN, + 0, + getFunction("default_action") + ), + }) + ), + new HermesRegex( + Pattern.compile("\\."), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_DOT, + 0, + getFunction("default_action") + ), + }) + ), + new HermesRegex( + Pattern.compile("\\["), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_LSQUARE, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("\\."), + Pattern.compile("\\]"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_DOT, + WdlTerminalIdentifier.TERMINAL_RSQUARE, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("\\{"), + Pattern.compile("in(?![a-zA-Z0-9_])"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_LBRACE, + WdlTerminalIdentifier.TERMINAL_IN, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("\\}"), + Pattern.compile("[a-zA-Z]([a-zA-Z0-9_])*"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_RBRACE, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, 0, getFunction("default_action") ), }) ), + })); + this.regex.put("raw_command", Arrays.asList(new HermesRegex[] { new HermesRegex( - Pattern.compile("\\("), + Pattern.compile("\\{"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_LPAREN, + WdlTerminalIdentifier.TERMINAL_RAW_CMD_START, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("\\)"), + Pattern.compile("\\}"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_RPAREN, + WdlTerminalIdentifier.TERMINAL_RAW_CMD_END, 0, getFunction("default_action") ), + new LexerAction("pop"), }) ), new HermesRegex( - Pattern.compile("\\["), + Pattern.compile("\\$\\{"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_LSQUARE, + WdlTerminalIdentifier.TERMINAL_CMD_PARAM_START, 0, getFunction("default_action") ), + new LexerStackPush("cmd_param"), }) ), new HermesRegex( - Pattern.compile("\\]"), + Pattern.compile("(.*?)(?=\\$\\{|\\})", Pattern.DOTALL), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_RSQUARE, + WdlTerminalIdentifier.TERMINAL_CMD_PART, 0, getFunction("default_action") ), }) ), + })); + this.regex.put("raw_command2", Arrays.asList(new HermesRegex[] { new HermesRegex( - Pattern.compile("\\+"), + Pattern.compile("<<<"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_RAW_CMD_START, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("\\*"), + Pattern.compile(">>>"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_ASTERISK, + WdlTerminalIdentifier.TERMINAL_RAW_CMD_END, 0, getFunction("default_action") ), + new LexerAction("pop"), }) ), new HermesRegex( - Pattern.compile("-"), + Pattern.compile("\\$\\{"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_DASH, + WdlTerminalIdentifier.TERMINAL_CMD_PARAM_START, 0, getFunction("default_action") ), + new LexerStackPush("cmd_param"), }) ), new HermesRegex( - Pattern.compile("/"), + Pattern.compile("(.*?)(?=\\$\\{|>>>)", Pattern.DOTALL), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_SLASH, + WdlTerminalIdentifier.TERMINAL_CMD_PART, 0, getFunction("default_action") ), }) ), + })); + this.regex.put("cmd_param", Arrays.asList(new HermesRegex[] { new HermesRegex( - Pattern.compile("%"), + Pattern.compile("\\s+"), Arrays.asList(new LexerOutput[] { - new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_PERCENT, - 0, - getFunction("default_action") - ), }) ), new HermesRegex( - Pattern.compile("<="), + Pattern.compile("\\}"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_LTEQ, + WdlTerminalIdentifier.TERMINAL_CMD_PARAM_END, 0, getFunction("default_action") ), + new LexerAction("pop"), }) ), new HermesRegex( - Pattern.compile("<"), + Pattern.compile("\\["), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_LT, + WdlTerminalIdentifier.TERMINAL_LSQUARE, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile(">="), + Pattern.compile("\\]"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_GTEQ, + WdlTerminalIdentifier.TERMINAL_RSQUARE, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile(">"), + Pattern.compile("="), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_GT, + WdlTerminalIdentifier.TERMINAL_EQUAL, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("!"), + Pattern.compile("\\+"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_NOT, + WdlTerminalIdentifier.TERMINAL_PLUS, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("-?[0-9]+\\.[0-9]+"), + Pattern.compile("\\*"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_FLOAT, + WdlTerminalIdentifier.TERMINAL_ASTERISK, 0, getFunction("default_action") ), @@ -5971,206 +6791,179 @@ private void lexer_init() throws SyntaxError { ), }) ), - })); - this.regex.put("task_fqn", Arrays.asList(new HermesRegex[] { - new HermesRegex( - Pattern.compile("\\s+"), - Arrays.asList(new LexerOutput[] { - }) - ), new HermesRegex( - Pattern.compile("[a-zA-Z]([a-zA-Z0-9_])*(\\.[a-zA-Z]([a-zA-Z0-9_])*)*"), + Pattern.compile("(true|false)(?![a-zA-Z0-9_])"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_NS_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_BOOLEAN, 0, getFunction("default_action") ), - new LexerAction("pop"), - }) - ), - })); - this.regex.put("scatter", Arrays.asList(new HermesRegex[] { - new HermesRegex( - Pattern.compile("\\s+"), - Arrays.asList(new LexerOutput[] { }) ), new HermesRegex( - Pattern.compile("\\)"), + Pattern.compile("(Array|Map|Object|Boolean|Int|Float|Uri|File|String)(?![a-zA-Z0-9_])(?![a-zA-Z0-9_])"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_RPAREN, + WdlTerminalIdentifier.TERMINAL_TYPE, 0, getFunction("default_action") ), - new LexerAction("pop"), }) ), new HermesRegex( - Pattern.compile("\\("), + Pattern.compile("[a-zA-Z]([a-zA-Z0-9_])*(?=\\s*=)"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_LPAREN, + WdlTerminalIdentifier.TERMINAL_CMD_ATTR_HINT, + -1, + getFunction("default_action") + ), + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("\\."), + Pattern.compile("[a-zA-Z]([a-zA-Z0-9_])*"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_DOT, + WdlTerminalIdentifier.TERMINAL_IDENTIFIER, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("\\["), + Pattern.compile(":"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_LSQUARE, + WdlTerminalIdentifier.TERMINAL_COLON, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("\\]"), + Pattern.compile(","), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_RSQUARE, + WdlTerminalIdentifier.TERMINAL_COMMA, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("in(?![a-zA-Z0-9_])"), + Pattern.compile("\\."), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_IN, + WdlTerminalIdentifier.TERMINAL_DOT, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("[a-zA-Z]([a-zA-Z0-9_])*"), + Pattern.compile("=="), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_DOUBLE_EQUAL, 0, getFunction("default_action") ), }) ), - })); - this.regex.put("raw_command", Arrays.asList(new HermesRegex[] { new HermesRegex( - Pattern.compile("\\{"), + Pattern.compile("\\|\\|"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_RAW_CMD_START, + WdlTerminalIdentifier.TERMINAL_DOUBLE_PIPE, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("\\}"), + Pattern.compile("\\&\\&"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_RAW_CMD_END, + WdlTerminalIdentifier.TERMINAL_DOUBLE_AMPERSAND, 0, getFunction("default_action") ), - new LexerAction("pop"), }) ), new HermesRegex( - Pattern.compile("\\$\\{"), + Pattern.compile("!="), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_CMD_PARAM_START, + WdlTerminalIdentifier.TERMINAL_NOT_EQUAL, 0, getFunction("default_action") ), - new LexerStackPush("cmd_param"), }) ), new HermesRegex( - Pattern.compile("(.*?)(?=\\$\\{|\\})", Pattern.DOTALL), + Pattern.compile("="), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_CMD_PART, + WdlTerminalIdentifier.TERMINAL_EQUAL, 0, getFunction("default_action") ), }) ), - })); - this.regex.put("raw_command2", Arrays.asList(new HermesRegex[] { new HermesRegex( - Pattern.compile("<<<"), + Pattern.compile("\\."), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_RAW_CMD_START, + WdlTerminalIdentifier.TERMINAL_DOT, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile(">>>"), + Pattern.compile("\\{"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_RAW_CMD_END, + WdlTerminalIdentifier.TERMINAL_LBRACE, 0, getFunction("default_action") ), - new LexerAction("pop"), }) ), new HermesRegex( - Pattern.compile("\\$\\{"), + Pattern.compile("\\}"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_CMD_PARAM_START, + WdlTerminalIdentifier.TERMINAL_RBRACE, 0, getFunction("default_action") ), - new LexerStackPush("cmd_param"), }) ), new HermesRegex( - Pattern.compile("(.*?)(?=\\$\\{|>>>)", Pattern.DOTALL), + Pattern.compile("\\("), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_CMD_PART, + WdlTerminalIdentifier.TERMINAL_LPAREN, 0, getFunction("default_action") ), }) ), - })); - this.regex.put("cmd_param", Arrays.asList(new HermesRegex[] { - new HermesRegex( - Pattern.compile("\\s+"), - Arrays.asList(new LexerOutput[] { - }) - ), new HermesRegex( - Pattern.compile("\\}"), + Pattern.compile("\\)"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_CMD_PARAM_END, + WdlTerminalIdentifier.TERMINAL_RPAREN, 0, getFunction("default_action") ), - new LexerAction("pop"), }) ), new HermesRegex( @@ -6194,95 +6987,100 @@ private void lexer_init() throws SyntaxError { }) ), new HermesRegex( - Pattern.compile("="), + Pattern.compile("\\+"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_EQUAL, + WdlTerminalIdentifier.TERMINAL_PLUS, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("\\?"), + Pattern.compile("\\*"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_QMARK, + WdlTerminalIdentifier.TERMINAL_ASTERISK, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("\\+"), + Pattern.compile("-"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_PLUS, + WdlTerminalIdentifier.TERMINAL_DASH, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("\\*"), + Pattern.compile("/"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_ASTERISK, + WdlTerminalIdentifier.TERMINAL_SLASH, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("[0-9]+"), + Pattern.compile("%"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_INTEGER, + WdlTerminalIdentifier.TERMINAL_PERCENT, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("(true|false)(?![a-zA-Z0-9_])"), + Pattern.compile("<="), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_BOOLEAN, + WdlTerminalIdentifier.TERMINAL_LTEQ, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("(Array|Map|Object|Boolean|Int|Float|Uri|File|String)(?![a-zA-Z0-9_])(?![a-zA-Z0-9_])"), + Pattern.compile("<"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_TYPE, + WdlTerminalIdentifier.TERMINAL_LT, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("[a-zA-Z]([a-zA-Z0-9_])*(?=\\s*=)"), + Pattern.compile(">="), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_CMD_ATTR_HINT, - -1, + WdlTerminalIdentifier.TERMINAL_GTEQ, + 0, getFunction("default_action") ), + }) + ), + new HermesRegex( + Pattern.compile(">"), + Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_GT, 0, getFunction("default_action") ), }) ), new HermesRegex( - Pattern.compile("[a-zA-Z]([a-zA-Z0-9_])*"), + Pattern.compile("!"), Arrays.asList(new LexerOutput[] { new LexerRegexOutput( - WdlTerminalIdentifier.TERMINAL_IDENTIFIER, + WdlTerminalIdentifier.TERMINAL_NOT, 0, getFunction("default_action") ), @@ -6308,6 +7106,26 @@ private void lexer_init() throws SyntaxError { ), }) ), + new HermesRegex( + Pattern.compile("-?[0-9]+\\.[0-9]+"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_FLOAT, + 0, + getFunction("default_action") + ), + }) + ), + new HermesRegex( + Pattern.compile("[0-9]+"), + Arrays.asList(new LexerOutput[] { + new LexerRegexOutput( + WdlTerminalIdentifier.TERMINAL_INTEGER, + 0, + getFunction("default_action") + ), + }) + ), })); } private void unrecognized_token(String string, int line, int col) throws SyntaxError { @@ -6386,6 +7204,7 @@ private int next(LexerContext lctx) throws SyntaxError { public List lex(String string, String resource) throws SyntaxError { LexerContext lctx = new LexerContext(string, resource); Object context = this.init(); + lctx.context = context; String string_copy = new String(string); if (this.regex == null) { lexer_init(); diff --git a/src/main/migrations/changelog.xml b/src/main/migrations/changelog.xml index 093e895d951..dda984a3a63 100644 --- a/src/main/migrations/changelog.xml +++ b/src/main/migrations/changelog.xml @@ -11,4 +11,6 @@ + + diff --git a/src/main/migrations/changesets/add_index_in_execution.xml b/src/main/migrations/changesets/add_index_in_execution.xml new file mode 100644 index 00000000000..44a71d3d308 --- /dev/null +++ b/src/main/migrations/changesets/add_index_in_execution.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/src/main/migrations/changesets/rename_iteration_to_index.xml b/src/main/migrations/changesets/rename_iteration_to_index.xml new file mode 100644 index 00000000000..a85483f7908 --- /dev/null +++ b/src/main/migrations/changesets/rename_iteration_to_index.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index aa17be771ec..c763472e414 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -37,26 +37,31 @@ backend { backend = "local" // Either "JES" or "local", case insensitive // If backend is JES, must supply a 'jes' stanza: - // jes - // applicationName - // project (i.e. google project name) - // baseExecutionBucket (GCS path where things will be written to) + //jes { + // applicationName = "" + // project = "" + // baseExecutionBucket = "" + // endpointUrl = "" + //} } // If authenticating with Google (e.g. if backend is 'JES') you must supply a top level stanza 'google': +//google { +// authScheme = "user" -// google -// authScheme - Either "service" for service account or "user" for user-based, case insensitive - // If "user" you must supply: - // userAuth - // user - // secretsFile - // dataStoreDir (dir to cache oauth credentials) - // You will be asked to do the oauth browser dance +// If authScheme is "user" +// userAuth { +// user = "" +// secretsFile = "" +// dataStoreDir = "" +// } - // If "service" you must supply: - // p12File - // serviceAccountId +// If authScheme is "service" +// serviceAuth { +// p12File = "" +// serviceAccountId = "" +// } +//} database { config = main.hsqldb diff --git a/src/main/resources/grammar.hgr b/src/main/resources/grammar.hgr index 77677a44139..ee6e0c501ab 100644 --- a/src/main/resources/grammar.hgr +++ b/src/main/resources/grammar.hgr @@ -19,12 +19,12 @@ grammar { } -> null r'#.*' -> null - r'task(?!{%_identifier_follow%})' -> :task + r'task(?!{%_identifier_follow%})' -> task(:task) r'(call)\s+' -> :call[1] @task_fqn - r'workflow(?!{%_identifier_follow%})' -> :workflow + r'workflow(?!{%_identifier_follow%})' -> workflow(:workflow) r'import(?!{%_identifier_follow%})' -> :import r'input(?!{%_identifier_follow%})' -> :input - r'output(?!{%_identifier_follow%})' -> :output + r'output(?!{%_identifier_follow%})' -> output(:output) r'as(?!{%_identifier_follow%})' -> :as r'if(?!{%_identifier_follow%})' -> :if r'while(?!{%_identifier_follow%})' -> :while @@ -73,14 +73,30 @@ grammar { r'>=' -> :gteq r'>' -> :gt r'!' -> :not + enum { + python: r'\?' + java: "\\?" + } -> :qmark r'-?[0-9]+\.[0-9]+' -> :float r'[0-9]+' -> :integer + mode { + r'\s+' -> null + r'\{' -> :lbrace + r'\}' -> :rbrace %pop + r',' -> :comma + r'\.' -> :dot + r'\*' -> :asterisk + enum { + python: r'{%_identifier%}(\.{%_identifier%})*' + java: "{%_identifier%}(\\.{%_identifier%})*" + } -> :fqn + } mode { r'\s+' -> null enum { python: r'{%_identifier%}(\.{%_identifier%})*' java: "{%_identifier%}(\\.{%_identifier%})*" - } -> :ns_identifier %pop + } -> :fqn %pop } mode { r'\s+' -> null @@ -120,10 +136,6 @@ grammar { r'\[' -> :lsquare r'\]' -> :rsquare r'=' -> :equal - enum { - python: r'\?' - java: "\\?" - } -> :qmark r'\+' -> :plus r'\*' -> :asterisk r'[0-9]+' -> :integer @@ -131,6 +143,35 @@ grammar { r'{%_type%}(?!{%_identifier_follow%})' -> :type r'{%_identifier%}(?=\s*=)' -> :cmd_attr_hint[] :identifier r'{%_identifier%}' -> :identifier + + # Expression tokens + r':' -> :colon + r',' -> :comma + r'\.' -> :dot + r'==' -> :double_equal + r'\|\|' -> :double_pipe + r'\&\&' -> :double_ampersand + r'!=' -> :not_equal + r'=' -> :equal + r'\.' -> :dot + r'\{' -> :lbrace + r'\}' -> :rbrace + r'\(' -> :lparen + r'\)' -> :rparen + r'\[' -> :lsquare + r'\]' -> :rsquare + r'\+' -> :plus + r'\*' -> :asterisk + r'-' -> :dash + r'/' -> :slash + r'%' -> :percent + r'<=' -> :lteq + r'<' -> :lt + r'>=' -> :gteq + r'>' -> :gt + r'!' -> :not + + # Literals enum { python: r'"([^\"]+)"' java: "\"([^\"]+)\"" @@ -139,22 +180,65 @@ grammar { python: r'\'([^\']+)\'' java: "'([^']+)'" } -> :string[1] + r'-?[0-9]+\.[0-9]+' -> :float + r'[0-9]+' -> :integer + } + + code << PYTHON + def init(): + return {'context': None} + def workflow(ctx, terminal, source_string, line, col): + ctx.user_context['context'] = 'workflow' + default_action(ctx, terminal, source_string, line, col) + def task(ctx, terminal, source_string, line, col): + ctx.user_context['context'] = 'task' + default_action(ctx, terminal, source_string, line, col) + def output(ctx, terminal, source_string, line, col): + if ctx.user_context['context'] == 'workflow': + ctx.stack.append('wf_output') + default_action(ctx, terminal, source_string, line, col) + PYTHON + + code << JAVA + private class WdlContext { + public String wf_or_task = null; + } + public Object init() { + return new WdlContext(); } + public void workflow(LexerContext ctx, TerminalIdentifier terminal, String source_string, int line, int col) { + ((WdlContext) ctx.context).wf_or_task = "workflow"; + default_action(ctx, terminal, source_string, line, col); + } + public void task(LexerContext ctx, TerminalIdentifier terminal, String source_string, int line, int col) { + ((WdlContext) ctx.context).wf_or_task = "task"; + default_action(ctx, terminal, source_string, line, col); + } + public void output(LexerContext ctx, TerminalIdentifier terminal, String source_string, int line, int col) { + WdlContext user_ctx = (WdlContext) ctx.context; + if (user_ctx.wf_or_task != null && user_ctx.wf_or_task.equals("workflow")) { + ctx.stack.push("wf_output"); + } + default_action(ctx, terminal, source_string, line, col); + } + JAVA } parser { + # Document: https://github.com/broadinstitute/wdl/blob/wdl2/SPEC.md#document $document = list($import) list($workflow_or_task) -> Document(imports=$0, definitions=$1) $workflow_or_task = $workflow | $task + # Import Statements: https://github.com/broadinstitute/wdl/blob/wdl2/SPEC.md#import-statements $import = :import :string optional($import_namespace) -> Import(uri=$1, namespace=$2) $import_namespace = :as :identifier -> $1 + + # Task Definition: https://github.com/broadinstitute/wdl/blob/wdl2/SPEC.md#task-definition $task = :task :identifier :lbrace list($declaration) list($sections) :rbrace -> Task(name=$1, declarations=$3, sections=$4) $sections = $command | $outputs | $runtime | $parameter_meta | $meta $command = :raw_command :raw_cmd_start list($command_part) :raw_cmd_end -> RawCommand(parts=$2) $command_part = :cmd_part | $cmd_param - $cmd_param = :cmd_param_start list($cmd_param_kv) optional(:string) optional($type_e) :identifier optional($postfix_quantifier) :cmd_param_end - -> CommandParameter(name=$4, type=$3, prefix=$2, attributes=$1, postfix=$5) + $cmd_param = :cmd_param_start list($cmd_param_kv) $e :cmd_param_end -> CommandParameter(attributes=$1, expr=$2) $cmd_param_kv = :cmd_attr_hint :identifier :equal $e -> CommandParameterAttr(key=$1, value=$3) - $postfix_quantifier = :qmark | :plus | :asterisk $outputs = :output :lbrace list($output_kv) :rbrace -> Outputs(attributes=$2) $output_kv = $type_e :identifier :equal $e -> Output(type=$0, var=$1, expression=$3) $runtime = :runtime $map -> Runtime(map=$1) @@ -163,11 +247,18 @@ grammar { $map = :lbrace list($kv) :rbrace -> $1 $kv = :identifier :colon $e -> RuntimeAttribute(key=$0, value=$2) + # Declarations: https://github.com/broadinstitute/wdl/blob/wdl2/SPEC.md#declarations + $declaration = $type_e optional($postfix_quantifier) :identifier optional($setter) -> Declaration(type=$0, postfix=$1, name=$2, expression=$3) + $setter = :equal $e -> $1 + $postfix_quantifier = :qmark | :plus + + # Types: https://github.com/broadinstitute/wdl/blob/wdl2/SPEC.md#types $type_e = parser { (*:left) $type_e = :type <=> :lsquare list($type_e, :comma) :rsquare -> Type(name=$0, subtype=$2) $type_e = :type } + # Expressions: https://github.com/broadinstitute/wdl/blob/wdl2/SPEC.md#expressions $e = parser { (*:left) $e = $e :double_pipe $e -> LogicalOr(lhs=$0, rhs=$2) (*:left) $e = $e :double_ampersand $e -> LogicalAnd(lhs=$0, rhs=$2) @@ -191,23 +282,27 @@ grammar { # TODO: is there a better object literal syntax? (*:left) $e = :object :lbrace list($object_kv, :comma) :rbrace -> ObjectLiteral(map=$2) (*:left) $e = :lsquare list($e, :comma) :rsquare -> ArrayLiteral(values=$1) + (*:left) $e = :lbrace list($map_kv, :comma) :rbrace -> MapLiteral(map=$1) (*:left) $e = :lparen $e :rparen -> $1 $e = :string $e = :identifier $e = :boolean $e = :integer $e = :float - $e = :dquote_string - $e = :squote_string } + $map_kv = $e :colon $e -> MapLiteralKv(key=$0, value=$2) + # Workflows: https://github.com/broadinstitute/wdl/blob/wdl2/SPEC.md#workflow-definition $workflow = :workflow :identifier :lbrace list($wf_body_element) :rbrace -> Workflow(name=$1, body=$3) - $wf_body_element = $call | $declaration | $while_loop | $if_stmt | $scatter - $call = :call :ns_identifier optional($alias) optional($call_body) -> Call(task=$1, alias=$2, body=$3) + $wf_body_element = $call | $declaration | $while_loop | $if_stmt | $scatter | $wf_outputs + $call = :call :fqn optional($alias) optional($call_body) -> Call(task=$1, alias=$2, body=$3) $call_body = :lbrace list($declaration) list($call_input) :rbrace -> CallBody(declarations=$1, io=$2) $call_input = :input :colon list($mapping, :comma) -> Inputs(map=$2) $mapping = :identifier :equal $e -> IOMapping(key=$0, value=$2) $alias = :as :identifier -> $1 + $wf_outputs = :output :lbrace list($wf_output, :comma) :rbrace -> WorkflowOutputs(outputs=$2) + $wf_output = :fqn optional($wf_output_wildcard) -> WorkflowOutput(fqn=$0, wildcard=$1) + $wf_output_wildcard = :dot :asterisk -> $1 $while_loop = :while :lparen $e :rparen :lbrace list($wf_body_element) :rbrace -> WhileLoop(expression=$2, body=$5) $if_stmt = :if :lparen $e :rparen :lbrace list($wf_body_element) :rbrace -> If(expression=$2, body=$5) @@ -215,8 +310,6 @@ grammar { $scatter = :scatter :lparen :identifier :in $e :rparen :lbrace list($wf_body_element) :rbrace -> Scatter(item=$2, collection=$4, body=$7) - $declaration = $type_e :identifier optional($setter) -> Declaration(type=$0, name=$1, expression=$2) - $setter = :equal $e -> $1 $object_kv = :identifier :colon $e -> ObjectKV(key=$0, value=$2) } } diff --git a/src/main/scala/cromwell/Main.scala b/src/main/scala/cromwell/Main.scala index 4d0ae9ab6b4..1890c6bd795 100644 --- a/src/main/scala/cromwell/Main.scala +++ b/src/main/scala/cromwell/Main.scala @@ -3,15 +3,12 @@ package cromwell import java.io.File import java.nio.file.Paths -import com.typesafe.config.ConfigFactory -import cromwell.binding._ -import cromwell.util.FileUtil.{EnhancedFile, EnhancedPath} -import cromwell.binding.formatter.{AnsiSyntaxHighlighter, SyntaxFormatter} +import cromwell.binding.formatter.{AnsiSyntaxHighlighter, HtmlSyntaxHighlighter, SyntaxFormatter} import cromwell.binding.{AstTools, _} -import cromwell.engine.workflow.{WorkflowManagerActor, SingleWorkflowRunnerActor} +import cromwell.engine.workflow.{SingleWorkflowRunnerActor, WorkflowManagerActor} import cromwell.parser.WdlParser.SyntaxError import cromwell.server.{CromwellServer, DefaultWorkflowManagerSystem, WorkflowManagerSystem} -import cromwell.util.FileUtil +import cromwell.util.FileUtil.EnhancedPath import org.slf4j.LoggerFactory import spray.json._ @@ -51,8 +48,17 @@ object Main extends App { } def highlight(args: Array[String]) { + if (args.length >= 2 && !Seq("html", "console").contains(args(1))) { + println("usage: highlight ") + System.exit(1) + } + + val visitor = args match { + case a if a.length >= 2 && args(1) == "html" => HtmlSyntaxHighlighter + case _ => AnsiSyntaxHighlighter + } val namespace = WdlNamespace.load(new File(args(0)), WorkflowManagerActor.BackendType) - val formatter = new SyntaxFormatter(AnsiSyntaxHighlighter) + val formatter = new SyntaxFormatter(visitor) println(formatter.format(namespace)) } diff --git a/src/main/scala/cromwell/binding/AstTools.scala b/src/main/scala/cromwell/binding/AstTools.scala index e33fb6cbfcc..c2751e66398 100644 --- a/src/main/scala/cromwell/binding/AstTools.scala +++ b/src/main/scala/cromwell/binding/AstTools.scala @@ -18,7 +18,8 @@ object AstTools { } def findTerminals(): Seq[Terminal] = AstTools.findTerminals(astNode) def findTopLevelMemberAccesses(): Iterable[Ast] = AstTools.findTopLevelMemberAccesses(astNode) - def sourceString(): String = astNode.asInstanceOf[Terminal].getSourceString + def sourceString: String = astNode.asInstanceOf[Terminal].getSourceString + def astListAsVector(): Seq[AstNode] = astNode.asInstanceOf[AstList].asScala.toVector def wdlType(wdlSyntaxErrorFormatter: WdlSyntaxErrorFormatter): WdlType = { astNode match { case t: Terminal => @@ -32,13 +33,18 @@ object AstTools { case "Array" => throw new SyntaxError(wdlSyntaxErrorFormatter.arrayMustHaveATypeParameter(t)) } case a: Ast => - val subtypes = a.getAttribute("subtype").asInstanceOf[AstList].asScala.toSeq + val subtypes = a.getAttribute("subtype").astListAsVector val typeTerminal = a.getAttribute("name").asInstanceOf[Terminal] - a.getAttribute("name").sourceString() match { + a.getAttribute("name").sourceString match { case "Array" => if (subtypes.size != 1) throw new SyntaxError(wdlSyntaxErrorFormatter.arrayMustHaveOnlyOneTypeParameter(typeTerminal)) val member = subtypes.head.wdlType(wdlSyntaxErrorFormatter) WdlArrayType(member) + case "Map" => + if (subtypes.size != 2) throw new SyntaxError(wdlSyntaxErrorFormatter.mapMustHaveExactlyTwoTypeParameters(typeTerminal)) + val keyType = subtypes(0).wdlType(wdlSyntaxErrorFormatter) + val valueType = subtypes(1).wdlType(wdlSyntaxErrorFormatter) + WdlMapType(keyType, valueType) } case null => WdlStringType case _ => throw new UnsupportedOperationException("Implement this later for compound types") @@ -55,10 +61,21 @@ object AstTools { case "true" => WdlBoolean.True case "false" => WdlBoolean.False } + // TODO: The below cases, ArrayLiteral and MapLiteral are brittle. They recursively call this wdlValue(). + // However, those recursive calls might contain full-on expressions instead of just other literals. This + // whole thing ought to be part of the regular expression evaluator, though I imagine that's non-trivial. case a: Ast if a.getName == "ArrayLiteral" && wdlType.isInstanceOf[WdlArrayType] => val arrType = wdlType.asInstanceOf[WdlArrayType] - val elements = a.getAttribute("values").asInstanceOf[AstList].asScala.toVector.map{node => node.wdlValue(arrType.memberType, wdlSyntaxErrorFormatter)} + val elements = a.getAttribute("values").astListAsVector map {node => node.wdlValue(arrType.memberType, wdlSyntaxErrorFormatter)} WdlArray(arrType, elements) + case a: Ast if a.getName == "MapLiteral" && wdlType.isInstanceOf[WdlMapType] => + val mapType = wdlType.asInstanceOf[WdlMapType] + val elements = a.getAttribute("map").asInstanceOf[AstList].asScala.toVector.map({ kvnode => + val k = kvnode.asInstanceOf[Ast].getAttribute("key").wdlValue(mapType.keyType, wdlSyntaxErrorFormatter) + val v = kvnode.asInstanceOf[Ast].getAttribute("value").wdlValue(mapType.valueType, wdlSyntaxErrorFormatter) + k -> v + }).toMap + WdlMap(mapType, elements) case _ => throw new SyntaxError(s"Could not convert AST to a $wdlType (${Option(astNode).getOrElse("No AST").toString})") } } @@ -66,7 +83,7 @@ object AstTools { implicit class EnhancedAstSeq(val astSeq: Seq[Ast]) extends AnyVal { def duplicatesByName: Seq[Ast] = { - astSeq.groupBy(_.getAttribute("name").sourceString()).collect({case (_ ,v) if v.size > 1 => v.head}).toVector + astSeq.groupBy(_.getAttribute("name").sourceString).collect({case (_ ,v) if v.size > 1 => v.head}).toVector } } @@ -82,6 +99,8 @@ object AstTools { val MemberAccess = "MemberAccess" val Runtime = "Runtime" val Declaration = "Declaration" + val WorkflowOutput = "WorkflowOutput" + val Scatter = "Scatter" } def getAst(wdlSource: WdlSource, resource: String): Ast = { @@ -162,7 +181,7 @@ object AstTools { case asts: Seq[Ast] if asts.isEmpty => Seq.empty[Ast] case asts: Seq[Ast] => /* Uses of .head here are assumed by the above code that ensures that there are no empty maps */ - val secondInputSectionIOMappings = asts(1).getAttribute("map").asInstanceOf[AstList].asScala.toVector + val secondInputSectionIOMappings = asts(1).getAttribute("map").astListAsVector val firstKeyTerminal = secondInputSectionIOMappings.head.asInstanceOf[Ast].getAttribute("key").asInstanceOf[Terminal] throw new SyntaxError(wdlSyntaxErrorFormatter.multipleInputStatementsOnCall(firstKeyTerminal)) } diff --git a/src/main/scala/cromwell/binding/Call.scala b/src/main/scala/cromwell/binding/Call.scala index 72d7bc226f7..5a7aa07a3c0 100644 --- a/src/main/scala/cromwell/binding/Call.scala +++ b/src/main/scala/cromwell/binding/Call.scala @@ -4,18 +4,20 @@ import cromwell.binding.AstTools.EnhancedAstNode import cromwell.parser.WdlParser.{Ast, SyntaxError, Terminal} import scala.util.{Success, Try} +import scala.language.postfixOps object Call { def apply(ast: Ast, namespaces: Seq[WdlNamespace], tasks: Seq[Task], - wdlSyntaxErrorFormatter: WdlSyntaxErrorFormatter): Call = { + wdlSyntaxErrorFormatter: WdlSyntaxErrorFormatter, + parent: Option[Scope]): Call = { val alias: Option[String] = ast.getAttribute("alias") match { case x: Terminal => Option(x.getSourceString) case _ => None } - val taskName = ast.getAttribute("task").sourceString() + val taskName = ast.getAttribute("task").sourceString val task = WdlNamespace.findTask(taskName, namespaces, tasks) getOrElse { throw new SyntaxError(wdlSyntaxErrorFormatter.callReferencesBadTaskName(ast, taskName)) } @@ -41,15 +43,17 @@ object Call { } } - new Call(alias, taskName, task, callInputSectionMappings) + new Call(alias, taskName, task, callInputSectionMappings, parent) } - private def processCallInput(ast: Ast, wdlSyntaxErrorFormatter: WdlSyntaxErrorFormatter): Map[String, WdlExpression] = - AstTools.callInputSectionIOMappings(ast, wdlSyntaxErrorFormatter).map {a => - val key = a.getAttribute("key").sourceString() + private def processCallInput(ast: Ast, + wdlSyntaxErrorFormatter: WdlSyntaxErrorFormatter): Map[String, WdlExpression] = { + AstTools.callInputSectionIOMappings(ast, wdlSyntaxErrorFormatter) map { a => + val key = a.getAttribute("key").sourceString val expression = new WdlExpression(a.getAttribute("value")) (key, expression) - }.toMap + } toMap + } } /** @@ -67,23 +71,10 @@ object Call { case class Call(alias: Option[String], taskFqn: FullyQualifiedName, task: Task, - inputMappings: Map[String, WdlExpression]) extends Scope { + inputMappings: Map[String, WdlExpression], + parent: Option[Scope]) extends Scope { val name: String = alias getOrElse taskFqn - /* - TODO/FIXME: Since a Workflow's Calls *must* have a parent a better way to handle this would be to use an ADT - where one type has a parent and one does not, and the Workflow can only take the former. I went down that - road a bit but Scope requires parent to be an Option[Scope] so it's turtles all the way down (well, up in this case) - */ - private var _parent: Option[Scope] = None - - def parent: Option[Scope] = _parent - - def setParent(parent: Scope) = { - if (this._parent.isEmpty) this._parent = Option(parent) - else throw new UnsupportedOperationException("parent is write-once") - } - private def unsatisfiedTaskInputs: Seq[TaskInput] = task.inputs.filterNot {case i => inputMappings.contains(i.name)} /** @@ -131,7 +122,7 @@ case class Call(alias: Option[String], /** * Instantiate the abstract command line corresponding to this call using the specified inputs. */ - def instantiateCommandLine(inputs: CallInputs): Try[String] = task.command.instantiate(inputs) + def instantiateCommandLine(inputs: CallInputs, functions: WdlFunctions): Try[String] = task.instantiateCommand(inputs, functions) /** * Return the docker configuration value associated with this `Call`, if any. diff --git a/src/main/scala/cromwell/binding/Declaration.scala b/src/main/scala/cromwell/binding/Declaration.scala index a09ceb361fc..a16f1a652af 100644 --- a/src/main/scala/cromwell/binding/Declaration.scala +++ b/src/main/scala/cromwell/binding/Declaration.scala @@ -9,7 +9,8 @@ object Declaration { Declaration( scopeFqn, ast.getAttribute("type").wdlType(wdlSyntaxErrorFormatter), - ast.getAttribute("name").sourceString(), + Option(ast.getAttribute("postfix")).map(_.sourceString), + ast.getAttribute("name").sourceString, ast.getAttribute("expression") match { case a: Ast => Some(WdlExpression(a)) case _ => None @@ -33,15 +34,15 @@ object Declaration { * * Both the definition of test_file and wf_string are declarations */ -case class Declaration(scopeFqn: FullyQualifiedName, wdlType: WdlType, name: String, expression: Option[WdlExpression]) { +case class Declaration(scopeFqn: FullyQualifiedName, wdlType: WdlType, postfixQuantifier: Option[String], name: String, expression: Option[WdlExpression]) { def asWorkflowInput: Option[WorkflowInput] = expression match { case Some(expr) => None - case None => Some(WorkflowInput(fullyQualifiedName, wdlType, postfixQuantifier = None)) + case None => Some(WorkflowInput(fullyQualifiedName, wdlType, postfixQuantifier)) } def asTaskInput: Option[TaskInput] = expression match { case Some(expr) => None - case None => Some(TaskInput(name, wdlType, postfixQuantifier = None)) + case None => Some(TaskInput(name, wdlType, postfixQuantifier)) } def fullyQualifiedName: FullyQualifiedName = s"$scopeFqn.$name" diff --git a/src/main/scala/cromwell/binding/Import.scala b/src/main/scala/cromwell/binding/Import.scala index 3404ad963da..cfc01ba1166 100644 --- a/src/main/scala/cromwell/binding/Import.scala +++ b/src/main/scala/cromwell/binding/Import.scala @@ -1,11 +1,11 @@ package cromwell.binding -import cromwell.parser.WdlParser.{AstNode, Ast} -import AstTools.EnhancedAstNode +import cromwell.binding.AstTools.EnhancedAstNode +import cromwell.parser.WdlParser.{Ast, AstNode} object Import { def apply(astNode: AstNode): Import = { - val uri = astNode.asInstanceOf[Ast].getAttribute("uri").sourceString() + val uri = astNode.asInstanceOf[Ast].getAttribute("uri").sourceString val importNamespace = Option(astNode.asInstanceOf[Ast].getAttribute("namespace")) Import(uri, importNamespace) } @@ -13,5 +13,5 @@ object Import { // FIXME: I dislike dragging the AST along but it's necessary for "compile" time error syntax highlighting, argh case class Import(uri: String, namespaceAst: Option[AstNode]) { - val namespace: Option[String] = namespaceAst map {_.sourceString()} + val namespace: Option[String] = namespaceAst map { _.sourceString } } diff --git a/src/main/scala/cromwell/binding/RuntimeAttributes.scala b/src/main/scala/cromwell/binding/RuntimeAttributes.scala index 82f78de41a2..c5938115a87 100644 --- a/src/main/scala/cromwell/binding/RuntimeAttributes.scala +++ b/src/main/scala/cromwell/binding/RuntimeAttributes.scala @@ -4,8 +4,8 @@ import com.google.api.services.genomics.model.Disk import cromwell.binding.AstTools.{AstNodeName, EnhancedAstNode} import cromwell.binding.RuntimeAttributes.{Defaults, LocalDisk} import cromwell.parser.RuntimeKey._ -import cromwell.parser.{RuntimeKey, BackendType, MemorySize} import cromwell.parser.WdlParser.{Ast, AstList} +import cromwell.parser.{BackendType, MemorySize, RuntimeKey} import org.slf4j.LoggerFactory import scala.collection.JavaConverters._ @@ -31,7 +31,7 @@ object RuntimeAttributes { def apply(ast: Ast, backendType: BackendType): RuntimeAttributes = { def processRuntimeAttribute(ast: Ast): (String, String) = { - (ast.getAttribute("key").sourceString(), ast.getAttribute("value").sourceString()) + (ast.getAttribute("key").sourceString, ast.getAttribute("value").sourceString) } def processRuntimeAttributes(astList: AstList): Map[String, String] = { diff --git a/src/main/scala/cromwell/binding/Scatter.scala b/src/main/scala/cromwell/binding/Scatter.scala new file mode 100644 index 00000000000..307869736e9 --- /dev/null +++ b/src/main/scala/cromwell/binding/Scatter.scala @@ -0,0 +1,27 @@ +package cromwell.binding + +import cromwell.parser.WdlParser.{Ast, Terminal} + +object Scatter { + /** + * @param index Index of the scatter block. The index is computed during tree generation to reflect wdl scatter blocks structure. + */ + def apply(ast: Ast, index: Int, parent: Option[Scope]): Scatter = { + val item = ast.getAttribute("item").asInstanceOf[Terminal].getSourceString + new Scatter(index, item, WdlExpression(ast.getAttribute("collection")), parent) + } +} + +/** + * Scatter class. + * @param index Index of the scatter block. The index is computed during tree generation to reflect wdl scatter blocks structure. + * @param item Item which this block is scattering over + * @param collection Wdl Expression corresponding to the collection this scatter is looping through + */ +case class Scatter(index: Int, item: String, collection: WdlExpression, parent: Option[Scope]) extends Scope { + + val name = s"$$scatter_$index" + + override def appearsInFQN = false + +} diff --git a/src/main/scala/cromwell/binding/Scope.scala b/src/main/scala/cromwell/binding/Scope.scala index 687af6cf035..d592b46c9b9 100644 --- a/src/main/scala/cromwell/binding/Scope.scala +++ b/src/main/scala/cromwell/binding/Scope.scala @@ -1,14 +1,151 @@ package cromwell.binding +import cromwell.binding.AstTools.AstNodeName +import cromwell.parser.WdlParser.{Ast, AstList} + +import scala.annotation.tailrec +import scala.collection.mutable.{Map, HashMap} +import scala.collection.JavaConverters._ + +object Scope { + + /** + * Generate a Scope Tree from an Ast. + * Ast must match a Scope (currently: Workflow, Scatter or Call) + * @throws UnsupportedOperationException if node does not match any supported Scopes + * @return generated Scope Tree. + */ + def generateTree(node: Ast, namespaces: Seq[WdlNamespace], tasks: Seq[Task], wdlSyntaxErrorFormatter: WdlSyntaxErrorFormatter): Scope = { + + val scopeIndexes: Map[Class[_ <: Scope], Int] = HashMap.empty + + /** + * Retrieve the list of children Asts from the AST body. + * Return empty seq if body is null or is not a list. + */ + def getChildrenList(ast: Ast): Seq[Ast] = Option(ast.getAttribute("body")) collect { + case list: AstList => list.asScala.toVector + } getOrElse Seq.empty collect { + case ast: Ast => ast + } + + /** + * Generate a scope from the ast parameter and all its descendants recursively. + * @return Some(instance of Scope) if the node has a Scope equivalent, None otherwise + */ + def generateScopeTree(node: Ast, namespaces: Seq[WdlNamespace], tasks: Seq[Task], wdlSyntaxErrorFormatter: WdlSyntaxErrorFormatter, parent: Option[Scope]): Option[Scope] = { + val scope: Option[Scope] = node match { + case w: Ast if w.getName == AstNodeName.Workflow => Option(Workflow(w, wdlSyntaxErrorFormatter, parent)) + case c: Ast if c.getName == AstNodeName.Call => Option(Call(c, namespaces, tasks, wdlSyntaxErrorFormatter, parent)) + case s: Ast if s.getName == AstNodeName.Scatter => Option(Scatter(s, scopeIndexes.getOrElse(classOf[Scatter], 0), parent)) + + /* Cases need to be added here to support new scopes */ + case _ => None + } + //Generate and set children recursively + scope foreach { sc => + //Increment index if needed + scopeIndexes.put(sc.getClass, scopeIndexes.getOrElse(sc.getClass, 0) + 1) + sc.setChildren(getChildrenList(node) flatMap { generateScopeTree(_, namespaces, tasks, wdlSyntaxErrorFormatter, Option(sc)) }) + } + scope + } + + generateScopeTree(node, namespaces, tasks, wdlSyntaxErrorFormatter, None) + .getOrElse(throw new UnsupportedOperationException("Input node cannot be instantiated as a Scope")) + } + + /** + * Generate a workflow from an Ast. The ast must be one of a workflow. + * @throws UnsupportedOperationException if the ast is not a workflow ast + * @return a workflow + */ + def generateWorkflow(ast: Ast, namespaces: Seq[WdlNamespace], tasks: Seq[Task], wdlSyntaxErrorFormatter: WdlSyntaxErrorFormatter): Workflow = { + ast.getName match { + case AstNodeName.Workflow => generateTree(ast, namespaces, tasks, wdlSyntaxErrorFormatter).asInstanceOf[Workflow] + case nonWorkflowAst => throw new UnsupportedOperationException(s"Ast is not a 'Workflow Ast' but a '$nonWorkflowAst Ast'") + } + } + + /** + * Collect Calls from a Seq of Scopes. + * @param scopes scopes to loop through + * @return Scopes instances that are Calls + */ + def collectCalls(scopes: Seq[Scope]): Seq[Call] = scopes collect { case s: Call => s } + + /** + * Collect all Calls from the given scope. + * @param scopes scope to gather Calls from + * @param calls for recursivity. Should be passed Nil in most cases. + * @return all Calls inside the scope + */ + @tailrec + def collectAllCalls(scopes: Seq[Scope], calls: Seq[Call]): Seq[Call] = scopes match { + case Nil => calls + case l => collectAllCalls(l.flatMap(_.children), calls ++ collectCalls(l)) + } + + /** + * Collect Scatters from a Seq of Scopes. + * @param scopes scopes to loop through + * @return Scopes instances that are Scatters + */ + def collectScatters(scopes: Seq[Scope]): Seq[Scatter] = scopes collect { case s: Scatter => s } + + /** + * Collect all Scatters from the given scope. + * @param scopes scope to gather Scatters from + * @param scatters for recursivity. Should be passed Nil in most cases. + * @return all Scatters inside the scope + */ + @tailrec + def collectAllScatters(scopes: Seq[Scope], scatters: Seq[Scatter]): Seq[Scatter] = scopes match { + case Nil => scatters + case l => collectAllScatters(l.flatMap(_.children), scatters ++ collectScatters(l)) + } + + @tailrec + def fullyQualifiedNameBuilder(scope: Option[Scope], fqn: String, fullDisplay: Boolean): String = scope match { + case None => fqn.tail //Strip away the first "." of the name + case Some(x: Scope) => fullyQualifiedNameBuilder(x.parent, (if (fullDisplay || x.appearsInFQN) s".${x.name}" else "") + fqn, fullDisplay) + } + +} + // FIXME: It'd be nice to have a notion of a parented and a not-parented Scope, see FIXME in Call about this trait Scope { + def name: String - def parent: Option[Scope] + def appearsInFQN: Boolean = true - def fullyQualifiedName: String = parent match { - case Some(x: Scope) => s"${x.fullyQualifiedName}.$name" - case _ => name + val parent: Option[Scope] + + private var _children: Seq[Scope] = Seq.empty + + def children: Seq[Scope] = _children + + def fullyQualifiedName = Scope.fullyQualifiedNameBuilder(Option(this), "", fullDisplay = false) + + def fullyQualifiedNameWithIndexScopes = Scope.fullyQualifiedNameBuilder(Option(this), "", fullDisplay = true) + + def setChildren(children: Seq[Scope]) = { + if (this._children.isEmpty) { + this._children = children + } else throw new UnsupportedOperationException("children is write-once") } + /** + * Convenience method to collect Calls from within a scope. + * @return all calls contained in this scope (recursively) + */ + def collectAllCalls = Scope.collectAllCalls(Seq(this), Nil) + + /** + * Convenience method to collect Scatters from within a scope. + * @return all scatters contained in this scope (recursively) + */ + def collectAllScatters = Scope.collectAllScatters(Seq(this), Nil) + } diff --git a/src/main/scala/cromwell/binding/Task.scala b/src/main/scala/cromwell/binding/Task.scala index ec26cbd8dcb..f0b65d385f5 100644 --- a/src/main/scala/cromwell/binding/Task.scala +++ b/src/main/scala/cromwell/binding/Task.scala @@ -1,50 +1,31 @@ package cromwell.binding +import java.util.regex.Pattern + import cromwell.binding.AstTools.{AstNodeName, EnhancedAstNode} -import cromwell.binding.command.{Command, ParameterCommandPart} +import cromwell.binding.command.{CommandPart, ParameterCommandPart, StringCommandPart} import cromwell.parser.BackendType import cromwell.parser.WdlParser._ +import scala.annotation.tailrec +import scala.collection.JavaConverters._ import scala.language.postfixOps +import scala.util.Try object Task { + val Ws = Pattern.compile("[\\ \\t]+") def apply(ast: Ast, backendType: BackendType, wdlSyntaxErrorFormatter: WdlSyntaxErrorFormatter): Task = { val name = ast.getAttribute("name").asInstanceOf[Terminal].getSourceString val declarations = ast.findAsts(AstNodeName.Declaration).map(Declaration(_, "name", wdlSyntaxErrorFormatter)) - - /* Examine all inputs to the task (which currently is only command parameters e.g. ${File x}) - * And ensure that any inputs that have the same name also have the exact same definition. - * For example having a command line of `./script ${File x} ${String x}` is conflicting. - */ - val commandParameters = ast.findAsts(AstNodeName.CommandParameter) - val parameterNames = commandParameters.map { _.getAttribute("name").sourceString() }.toSet - parameterNames.foreach { name => - val paramsWithSameName = commandParameters.filter { - _.getAttribute("name").sourceString == name - } - ensureCommandParameterAstsMatch(paramsWithSameName, ast, wdlSyntaxErrorFormatter) - } - val commandAsts = ast.findAsts(AstNodeName.Command) - if (commandAsts.size != 1) throw new UnsupportedOperationException("Expecting only one Command AST") - val command = Command(commandAsts.head, wdlSyntaxErrorFormatter) - val outputs = ast.findAsts(AstNodeName.Output) map {TaskOutput(_, wdlSyntaxErrorFormatter)} - new Task(name, declarations, command, outputs, ast, backendType) - } - - private def ensureCommandParameterAstsMatch(paramAsts: Seq[Ast], taskAst: Ast, wdlSyntaxErrorFormatter: WdlSyntaxErrorFormatter) = { - paramAsts.headOption.foreach { firstParamAst => - val sentinel = ParameterCommandPart(firstParamAst, wdlSyntaxErrorFormatter) - paramAsts.foreach { paramAst => - val parsed = ParameterCommandPart(paramAst, wdlSyntaxErrorFormatter) - if (parsed != sentinel) - throw new SyntaxError(wdlSyntaxErrorFormatter.parametersWithSameNameMustHaveSameDefinition( - taskAst.getAttribute("name").asInstanceOf[Terminal], - paramAst.getAttribute("name").asInstanceOf[Terminal], - paramAsts.head.getAttribute("name").asInstanceOf[Terminal] - )) - } + if (commandAsts.size != 1) throw new UnsupportedOperationException("Expecting exactly one Command section") + val commandTemplate = commandAsts.head.getAttribute("parts").asInstanceOf[AstList].asScala.toVector map { + case x: Terminal => new StringCommandPart(x.getSourceString) + case x: Ast => ParameterCommandPart(x, wdlSyntaxErrorFormatter) } + + val outputs = ast.findAsts(AstNodeName.Output) map { TaskOutput(_, wdlSyntaxErrorFormatter) } + Task(name, declarations, commandTemplate, outputs, ast, backendType) } } @@ -52,27 +33,122 @@ object Task { * Represents a `task` declaration in a WDL file * * @param name Name of the task - * @param command Abstract command defined in the `command` section + * @param declarations Any declarations (e.g. String something = "hello") defined in the task + * @param commandTemplate Sequence of command pieces, essentially a parsed command template * @param outputs Set of defined outputs in the `output` section of the task + * @param ast The syntax tree from which this was built. + * @param backendType which backend this task is meant to run on. */ case class Task(name: String, declarations: Seq[Declaration], - command: Command, + commandTemplate: Seq[CommandPart], outputs: Seq[TaskOutput], ast: Ast, backendType: BackendType) extends Executable { + import Task._ + /** + * Attributes defined in the runtime {...} section of a WDL task + */ + val runtimeAttributes = RuntimeAttributes(ast, backendType) + + /** + * Inputs to this task, as locally qualified names + * + * @return Seq[TaskInput] where TaskInput contains the input + * name & type as well as any postfix quantifiers (?, +) + */ + val inputs: Seq[TaskInput] = for (declaration <- declarations; input <- declaration.asTaskInput) yield input + // TODO: I think TaskInput can be replaced by Declaration + + /** + * Given a map of task-local parameter names and WdlValues, create a command String. + * + * Instantiating a command line is the process of taking a command in this form: + * + * {{{ + * sh script.sh ${var1} -o ${var2} + * }}} + * + * This command is stored as a `Seq[CommandPart]` in the `Command` class (e.g. [sh script.sh, ${var1}, -o, ${var2}]). + * Then, given a map of variable -> value: + * + * {{{ + * { + * "var1": "foo", + * "var2": "bar" + * } + * }}} + * + * It calls instantiate() on each part, and passes this map. The ParameterCommandPart are the ${var1} and ${var2} + * pieces and they lookup var1 and var2 in that map. + * + * The command that's returned from Command.instantiate() is: + * + * + * {{{sh script.sh foo -o bar}}} + * + * @param parameters Parameter values + * @return String instantiation of the command + */ + def instantiateCommand(parameters: CallInputs, functions: WdlFunctions = new NoFunctions): Try[String] = { + Try(normalize(commandTemplate.map(_.instantiate(declarations, parameters, functions)).mkString(""))) + } + + def commandTemplateString: String = normalize(commandTemplate.map(_.toString).mkString) + /** - * Inputs to this task, as task-local names (i.e. not fully-qualified) + * 1) Remove all leading newline chars + * 2) Remove all trailing newline AND whitespace chars + * 3) Remove all *leading* whitespace that's common among every line in the input string + * + * For example, the input string: + * + * " + * first line + * second line + * third line + * + * " * - * @return Map of input name to type for that input + * Would be normalized to: + * + * "first line + * second line + * third line" + * + * @param s String to process + * @return String which has common leading whitespace removed from each line */ - val inputs: Seq[TaskInput] = { - val commandInputs = command.inputs - val declarationInputs = for(declaration <- declarations; input <- declaration.asTaskInput) yield input - commandInputs ++ declarationInputs + private def normalize(s: String): String = { + val trimmed = stripAll(s, "\r\n", "\r\n \t") + val parts = trimmed.split("[\\r\\n]+") + val indent = parts.map(leadingWhitespaceCount).min + parts.map(_.substring(indent)).mkString("\n") } - val runtimeAttributes = RuntimeAttributes(ast, backendType) + private def leadingWhitespaceCount(s: String): Int = { + val matcher = Ws.matcher(s) + if (matcher.lookingAt) matcher.end else 0 + } + + private def stripAll(s: String, startChars: String, endChars: String): String = { + /* https://stackoverflow.com/questions/17995260/trimming-strings-in-scala */ + @tailrec + def start(n: Int): String = { + if (n == s.length) "" + else if (startChars.indexOf(s.charAt(n)) < 0) end(n, s.length) + else start(1 + n) + } + + @tailrec + def end(a: Int, n: Int): String = { + if (n <= a) s.substring(a, n) + else if (endChars.indexOf(s.charAt(n - 1)) < 0) s.substring(a, n) + else end(a, n - 1) + } + + start(0) + } - override def toString: String = s"[Task name=$name command=$command]" + override def toString: String = s"[Task name=$name commandTemplate=$commandTemplate}]" } diff --git a/src/main/scala/cromwell/binding/TaskOutput.scala b/src/main/scala/cromwell/binding/TaskOutput.scala index 40940f83780..dc36efba124 100644 --- a/src/main/scala/cromwell/binding/TaskOutput.scala +++ b/src/main/scala/cromwell/binding/TaskOutput.scala @@ -1,13 +1,13 @@ package cromwell.binding +import cromwell.binding.AstTools.EnhancedAstNode import cromwell.binding.types.WdlType -import AstTools.EnhancedAstNode import cromwell.parser.WdlParser.Ast object TaskOutput { def apply(ast: Ast, syntaxErrorFormatter: WdlSyntaxErrorFormatter): TaskOutput = { val wdlType = ast.getAttribute("type").wdlType(syntaxErrorFormatter) - val name = ast.getAttribute("var").sourceString() + val name = ast.getAttribute("var").sourceString val expression = ast.getAttribute("expression") new TaskOutput(name, wdlType, new WdlExpression(expression)) } diff --git a/src/main/scala/cromwell/binding/WdlExpression.scala b/src/main/scala/cromwell/binding/WdlExpression.scala index 4a8fb3ba81b..bee69172aff 100644 --- a/src/main/scala/cromwell/binding/WdlExpression.scala +++ b/src/main/scala/cromwell/binding/WdlExpression.scala @@ -1,12 +1,11 @@ package cromwell.binding -import cromwell.binding.WdlExpression.ScopedLookupFunction import cromwell.binding.formatter.{NullSyntaxHighlighter, SyntaxHighlighter} -import cromwell.binding.types.{WdlType, WdlArrayType, WdlExpressionType} +import cromwell.binding.types._ import cromwell.binding.values._ -import cromwell.engine.EngineFunctions import cromwell.parser.WdlParser import cromwell.parser.WdlParser.{Ast, AstList, AstNode, Terminal} +import cromwell.binding.AstTools.EnhancedAstNode import scala.collection.JavaConverters._ import scala.util.{Failure, Success, Try} @@ -14,66 +13,93 @@ import scala.util.{Failure, Success, Try} class WdlExpressionException(message: String = null, cause: Throwable = null) extends RuntimeException(message, cause) object WdlExpression { + + implicit class AstForExpressions(val ast: Ast) extends AnyVal { + def isFunctionCall: Boolean = ast.getName == "FunctionCall" + def isBinaryOperator: Boolean = BinaryOperators.contains(ast.getName) + def isUnaryOperator: Boolean = UnaryOperators.contains(ast.getName) + def functionName: String = ast.getAttribute("name").asInstanceOf[Terminal].getSourceString + def isMemberAccess: Boolean = ast.getName == "MemberAccess" + def isArrayLiteral: Boolean = ast.getName == "ArrayLiteral" + def isAllowedInnerFunctionCall: Boolean = ast.isFunctionCall && AllowedInnerFunctionCalls.contains(ast.functionName) + def params = ast.getAttribute("params").asInstanceOf[AstList].asScala.toVector + def name = ast.getAttribute("name").asInstanceOf[Terminal].getSourceString + + def isFunctionCallWithOneFileParameter: Boolean = ( + ast.isFunctionCall + && ast.params.size == 1 + && PreEvaluableFunctionsWithSingleParameter.contains(ast.functionName)) + } + + implicit class AstNodeForExpressions(val astNode: AstNode) extends AnyVal { + def containsFunctionCalls: Boolean = + astNode match { + case a: Ast if a.isFunctionCall => true + case a: Ast if a.isBinaryOperator => + val lhs = a.getAttribute("lhs") + val rhs = a.getAttribute("rhs") + lhs.containsFunctionCalls || rhs.containsFunctionCalls + case a: Ast if a.isUnaryOperator => + val rhs = a.getAttribute("expression") + rhs.containsFunctionCalls + case _ => false + } + } + val parser = new WdlParser() /** Maps from a locally qualified name to a WdlValue. */ type ScopedLookupFunction = String => WdlValue - def binaryOperators = Set( + val BinaryOperators = Set( "Add", "Subtract", "Multiply", "Divide", "Remainder", "GreaterThan", "LessThan", "GreaterThanOrEqual", "LessThanOrEqual", "Equals", "NotEquals", "LogicalAnd", "LogicalOr" ) - val unaryOperators = Set("LogicalNot", "UnaryPlus", "UnaryNegation") + val UnaryOperators = Set("LogicalNot", "UnaryPlus", "UnaryNegation") - val preEvaluableFunctions_SingleParameter: Seq[String] = Seq("read_int", "read_string") + val PreEvaluableFunctionsWithSingleParameter: Seq[String] = Seq("read_int", "read_string") - def functionCall(a: Ast): Boolean = a.getName == "FunctionCall" + // Function calls which can be called from within other function calls. + // e.g. read_int(stdout()) is fine but read_int(read_int(stdout)) is not. + val AllowedInnerFunctionCalls = Seq[String]("stdout", "stderr") - def binaryOperator(a: Ast): Boolean = binaryOperators.contains(a.getName) - - def unaryOperator(a: Ast): Boolean = unaryOperators.contains((a.getName)) - - def functionCallWithOneFileParameter(a: Ast): Boolean = ( - functionCall(a) - && a.getAttribute("params").asInstanceOf[AstList].asScala.toVector.size == 1 - && preEvaluableFunctions_SingleParameter.contains(a.getAttribute("name").asInstanceOf[Terminal].getSourceString)) - /** * Look within the expression for filenames which aren't explicitly listed as outputs. */ def preevaluateExpressionForFilenames(ast: AstNode, lookup: ScopedLookupFunction, functions: WdlFunctions): Try[Seq[WdlFile]] = { ast match { // This is the only case which actually pre-evaluates anything. The other cases are just buck-passers: - case a: Ast if functionCallWithOneFileParameter(a) => { - // Test the pre-evaluation would be valid by using dummy functions: - val innerExpression = a.getAttribute("params").asInstanceOf[AstList].asScala.toVector.head - val dummyEvaluation = evaluate(innerExpression, lookup, new DummyPreEvaluationFunctions()) - // If dummyEvaluation succeeded, run the real evaluation instead and match against it: - dummyEvaluation.flatMap( _ => evaluate(innerExpression, lookup, functions)) match { - case Success(value) => Success(Seq(WdlFile(value.valueString))) - case Failure(error) => Failure(error) + case a: Ast if a.isFunctionCallWithOneFileParameter => + val innerExpression = a.params.head + innerExpression match { + case innerAst: Ast if innerAst.containsFunctionCalls => + // Only allow function calls if there's only one and its on the allowed list: + if (innerAst.isAllowedInnerFunctionCall) { + Success(Seq.empty) + } else { + Failure(new IllegalArgumentException(s"Invalid inner function call in $innerExpression")) + } + case _ => evaluate(innerExpression, lookup, functions) match { + case Success(value) => Success(Seq(WdlFile(value.valueString))) + case Failure(e) => Failure(e) + } } - } // Binary operators - find filenames in sub-expressions and merge the lists: - case a: Ast if binaryOperator(a) => { + case a: Ast if a.isBinaryOperator => val lhs = preevaluateExpressionForFilenames(a.getAttribute("lhs"), lookup, functions) val rhs = preevaluateExpressionForFilenames(a.getAttribute("rhs"), lookup, functions) // Recurse both sides and add the lists together: lhs match { - case Success(lhsValue) => { + case Success(lhsValue) => rhs match { - case Success(rhsValue) => { - Success(Seq(lhsValue,rhsValue).flatten) - } + case Success(rhsValue) => Success(Seq(lhsValue, rhsValue).flatten) case Failure(error) => Failure(error) } - } case Failure(error) => Failure(error) } - } - case a: Ast if unaryOperator(a) => preevaluateExpressionForFilenames(a.getAttribute("expression"), lookup, functions) + case a: Ast if a.isUnaryOperator => preevaluateExpressionForFilenames(a.getAttribute("expression"), lookup, functions) case _ => Success(Seq()) } @@ -87,14 +113,14 @@ object WdlExpression { def evaluate(ast: AstNode, lookup: ScopedLookupFunction, functions: WdlFunctions, interpolateStrings: Boolean = false): Try[WdlValue] = { ast match { - case t: Terminal if t.getTerminalStr == "identifier" => Success(lookup(t.getSourceString)) + case t: Terminal if t.getTerminalStr == "identifier" => Try(lookup(t.getSourceString)) case t: Terminal if t.getTerminalStr == "integer" => Success(WdlInteger(t.getSourceString.toInt)) case t: Terminal if t.getTerminalStr == "float" => Success(WdlFloat(t.getSourceString.toDouble)) case t: Terminal if t.getTerminalStr == "boolean" => Success(WdlBoolean(t.getSourceString == "true")) case t: Terminal if t.getTerminalStr == "string" => val strValue = if (interpolateStrings) interpolate(t.getSourceString, lookup) else t.getSourceString Success(WdlString(strValue)) - case a: Ast if binaryOperators.contains(a.getName) => + case a: Ast if a.isBinaryOperator => val lhs = evaluate(a.getAttribute("lhs"), lookup, functions, interpolateStrings) val rhs = evaluate(a.getAttribute("rhs"), lookup, functions, interpolateStrings) a.getName match { @@ -113,7 +139,7 @@ object WdlExpression { case "LogicalAnd" => for(l <- lhs; r <- rhs) yield l.and(r).get case _ => Failure(new WdlExpressionException(s"Invalid operator: ${a.getName}")) } - case a: Ast if unaryOperators.contains(a.getName) => + case a: Ast if a.isUnaryOperator => val expression = evaluate(a.getAttribute("expression"), lookup, functions, interpolateStrings) a.getName match { case "LogicalNot" => for(e <- expression) yield e.not.get @@ -121,8 +147,8 @@ object WdlExpression { case "UnaryNegation" => for(e <- expression) yield e.unaryMinus.get case _ => Failure(new WdlExpressionException(s"Invalid operator: ${a.getName}")) } - case a: Ast if a.getName == "ArrayLiteral" => - val evaluatedElements = a.getAttribute("values").asInstanceOf[AstList].asScala.toVector map {x => + case a: Ast if a.isArrayLiteral => + val evaluatedElements = a.getAttribute("values").astListAsVector map {x => evaluate(x, lookup, functions, interpolateStrings) } evaluatedElements.partition {_.isSuccess} match { @@ -130,16 +156,25 @@ object WdlExpression { val message = failures.collect {case f: Failure[_] => f.exception.getMessage}.mkString("\n") Failure(new WdlExpressionException(s"Could not evaluate expression:\n$message")) case (successes, _) => - successes.map{_.get.wdlType}.toSet match { - case s:Set[WdlType] if s.isEmpty => - Failure(new WdlExpressionException(s"Can't have empty array declarations (can't infer type)")) - case s:Set[WdlType] if s.size == 1 => - Success(WdlArray(WdlArrayType(s.head), successes.map{_.get}.toSeq)) - case _ => - Failure(new WdlExpressionException("Arrays must have homogeneous types")) - } + for (subtype <- WdlType.homogeneousType(successes.map(_.get))) + yield WdlArray(WdlArrayType(subtype), successes.map(_.get)) + } + case a: Ast if a.getName == "MapLiteral" => + val evaluatedMap = a.getAttribute("map").astListAsVector map { kv => + val key = evaluate(kv.asInstanceOf[Ast].getAttribute("key"), lookup, functions, interpolateStrings) + val value = evaluate(kv.asInstanceOf[Ast].getAttribute("value"), lookup, functions, interpolateStrings) + key -> value } - case a: Ast if a.getName == "MemberAccess" => + + val flattenedTries = evaluatedMap flatMap { case (k,v) => Seq(k,v) } + flattenedTries partition {_.isSuccess} match { + case (_, failures) if failures.nonEmpty => + val message = failures.collect { case f: Failure[_] => f.exception.getMessage }.mkString("\n") + Failure(new WdlExpressionException(s"Could not evaluate expression:\n$message")) + case (successes, _) => + WdlMapType(WdlAnyType, WdlAnyType).coerceRawValue(evaluatedMap.map({ case (k, v) => k.get -> v.get }).toMap) + } + case a: Ast if a.isMemberAccess => a.getAttribute("rhs") match { case rhs:Terminal if rhs.getTerminalStr == "identifier" => evaluate(a.getAttribute("lhs"), lookup, functions, interpolateStrings).flatMap { @@ -153,11 +188,9 @@ object WdlExpression { } case _ => Failure(new WdlExpressionException("Right-hand side of expression must be identifier")) } - case a: Ast if functionCall(a) => + case a: Ast if a.isFunctionCall => val name = a.getAttribute("name").asInstanceOf[Terminal].getSourceString - val params = a.getAttribute("params").asInstanceOf[AstList].asScala.toVector map { - evaluate(_, lookup, functions, interpolateStrings) - } + val params = a.params map { evaluate(_, lookup, functions, interpolateStrings) } functions.getFunction(name)(params) } } @@ -175,7 +208,7 @@ object WdlExpression { case t: Terminal if t.getTerminalStr == "integer" => t.getSourceString case t: Terminal if t.getTerminalStr == "float" => t.getSourceString case t: Terminal if t.getTerminalStr == "string" => s""""${t.getSourceString}"""" - case a:Ast if binaryOperators.contains(a.getName) => { + case a:Ast if a.isBinaryOperator => val lhs = toString(a.getAttribute("lhs"), highlighter) val rhs = toString(a.getAttribute("rhs"), highlighter) a.getName match { @@ -193,27 +226,27 @@ object WdlExpression { case "LogicalOr" => s"$lhs || $rhs" case "LogicalAnd" => s"$lhs && $rhs" } - } - case a:Ast if a.getName == "FunctionCall" => { - val name = a.getAttribute("name").asInstanceOf[Terminal].getSourceString - val params = a.getAttribute("params").asInstanceOf[AstList].asScala.toVector.map {a => toString(a, highlighter)} - s"${highlighter.function(name)}(${params.mkString(", ")})" - } - case a:Ast if a.getName == "MemberAccess" => { + case a: Ast if a.isFunctionCall => + val params = a.params map { a => toString(a, highlighter) } + s"${highlighter.function(a.name)}(${params.mkString(", ")})" + case a: Ast if a.isMemberAccess => val lhs = toString(a.getAttribute("lhs"), highlighter) val rhs = toString(a.getAttribute("rhs"), highlighter) s"$lhs.$rhs" - } } } } case class WdlExpression(ast: AstNode) extends WdlValue { + + import WdlExpression._ + override val wdlType = WdlExpressionType def evaluate(lookup: ScopedLookupFunction, functions: WdlFunctions, interpolateStrings: Boolean = false): Try[WdlValue] = WdlExpression.evaluate(ast, lookup, functions, interpolateStrings) def preevaluateExpressionForFilenames(lookup: ScopedLookupFunction, functions: WdlFunctions): Try[Seq[WdlFile]] = WdlExpression.preevaluateExpressionForFilenames(ast, lookup: ScopedLookupFunction, functions: WdlFunctions) + def containsFunctionCall = ast.containsFunctionCalls def toString(highlighter: SyntaxHighlighter): String = { WdlExpression.toString(ast, highlighter) } @@ -225,15 +258,3 @@ trait WdlFunctions { def getFunction(name: String): WdlFunction } - - -class DummyPreEvaluationFunctions extends EngineFunctions { - // These cannot be evaluated before running the operation, so quickly fail the pre-evaluation test. - override protected def read_int(params: Seq[Try[WdlValue]]): Try[WdlInteger] = Failure(new UnsupportedOperationException("Unable to pre-evaluate read_int")) - override protected def read_string(params: Seq[Try[WdlValue]]): Try[WdlString] = Failure(new UnsupportedOperationException("Unable to pre-evaluate read_string")) - override protected def read_lines(params: Seq[Try[WdlValue]]): Try[WdlArray] = Failure(new UnsupportedOperationException("Unable to pre-evaluate read_lines")) - - // These can be evaluated before running the operation so provide dummy values during the pre-evaluation test. - override protected def stdout(params: Seq[Try[WdlValue]]): Try[WdlFile] = Success(WdlFile("/test/value")) - override protected def stderr(params: Seq[Try[WdlValue]]): Try[WdlFile] = Success(WdlFile("/test/value")) -} \ No newline at end of file diff --git a/src/main/scala/cromwell/binding/WdlNamespace.scala b/src/main/scala/cromwell/binding/WdlNamespace.scala index be49a39523b..9e0f642d059 100644 --- a/src/main/scala/cromwell/binding/WdlNamespace.scala +++ b/src/main/scala/cromwell/binding/WdlNamespace.scala @@ -3,14 +3,11 @@ package cromwell.binding import java.io.File import cromwell.binding.AstTools.{AstNodeName, EnhancedAstNode, EnhancedAstSeq} -import cromwell.binding.command.ParameterCommandPart import cromwell.binding.types._ import cromwell.binding.values._ -import cromwell.parser.{BackendType, WdlParser} import cromwell.parser.WdlParser._ +import cromwell.parser.{BackendType, WdlParser} import cromwell.util.FileUtil.EnhancedFile -import AstTools.{AstNodeName, EnhancedAstNode, EnhancedAstSeq} -import cromwell.util.FileUtil import scala.collection.JavaConverters._ import scala.language.postfixOps @@ -67,20 +64,10 @@ case class NamespaceWithWorkflow(importedAs: Option[String], def coerceRawInput(input: WorkflowInput): Try[Option[WdlValue]] = input.fqn match { case _ if rawInputs.contains(input.fqn) => val rawValue = rawInputs.get(input.fqn).get - val coercionFailure = Failure(new UnsatisfiedInputsException(s"Could not coerce value for '${input.fqn}' into: ${input.wdlType}")) input.wdlType.coerceRawValue(rawValue) match { case Success(value) => Success(Some(value)) - case _ if input.postfixQuantifier.isDefined && input.wdlType.isInstanceOf[WdlArrayType] && ParameterCommandPart.PostfixQuantifiersThatAcceptArrays.contains(input.postfixQuantifier.get) => - val memberType = input.wdlType.asInstanceOf[WdlArrayType].memberType - memberType.coerceRawValue(rawValue) match { - case Success(value) => Success(Some(WdlArray(WdlArrayType(memberType), Seq(value)))) - case _ => coercionFailure - } - case _ => coercionFailure + case _ => Failure(new UnsatisfiedInputsException(s"Could not coerce value for '${input.fqn}' into: ${input.wdlType}")) } - /* TODO: if coercion fails above, it might be because you tried passing a single value to a parameter that can - * take multiple values (e.g. `${sep=" " String var+}`). If this is the case, coerce to - */ case _ => input.optional match { case true => Success(None) @@ -128,10 +115,6 @@ case class NamespaceWithWorkflow(importedAs: Option[String], def staticDeclarationsRecursive(userInputs: WorkflowCoercedInputs): Try[WorkflowCoercedInputs] = { import scala.collection.mutable val collected = mutable.Map[String, WdlValue]() - class NoFunctions extends WdlFunctions { - def getFunction(name: String): WdlFunction = throw new UnsupportedOperationException("No functions should be called in this test") - } - val allDeclarations = workflow.declarations ++ workflow.calls.flatMap {_.task.declarations} val evaluatedDeclarations = allDeclarations.filter {_.expression.isDefined}.map {decl => @@ -273,7 +256,7 @@ object WdlNamespace { for { i <- imports namespaceAst <- i.namespaceAst - task <- findTask(namespaceAst.sourceString(), namespaces, tasks) + task <- findTask(namespaceAst.sourceString, namespaces, tasks) } yield {throw new SyntaxError(wdlSyntaxErrorFormatter.taskAndNamespaceHaveSameName(task.ast, namespaceAst.asInstanceOf[Terminal]))} // Detect duplicated task names @@ -352,11 +335,10 @@ object NamespaceWithWorkflow { for { i <- imports namespaceAst <- i.namespaceAst - if namespaceAst.sourceString() == workflowAst.getAttribute("name").sourceString() + if namespaceAst.sourceString == workflowAst.getAttribute("name").sourceString } yield {throw new SyntaxError(wdlSyntaxErrorFormatter.workflowAndNamespaceHaveSameName(workflowAst, namespaceAst.asInstanceOf[Terminal]))} - val calls = workflowAst.findAsts(AstNodeName.Call) map {Call(_, namespaces, tasks, wdlSyntaxErrorFormatter)} - val workflow: Workflow = Workflow(workflowAst, wdlSyntaxErrorFormatter, calls) + val workflow: Workflow = Scope.generateWorkflow(workflowAst, namespaces, tasks, wdlSyntaxErrorFormatter) // FIXME: This block is run for its side effect of blowing up on the .get (I believe!) - Should there be a real syntax error? // FIXME: It took me a while to understand the logic of the original code & I'm not sure this comment is correct? @@ -382,11 +364,11 @@ object NamespaceWithWorkflow { def getCallFromMemberAccessAst(ast: Ast, workflow: Workflow, wdlSyntaxErrorFormatter: WdlSyntaxErrorFormatter): Try[Call] = { def callFromName(name: String): Try[Call] = { workflow.calls.find(_.name == name) match { - case Some(c:Call) => Success(c) + case Some(c: Call) => Success(c) case _ => Failure(new SyntaxError(wdlSyntaxErrorFormatter.undefinedMemberAccess(ast))) } } - val rhs = ast.getAttribute("rhs").sourceString() + val rhs = ast.getAttribute("rhs").sourceString /** * The right-hand side of a member-access AST should always be interpreted as a String @@ -409,11 +391,11 @@ object NamespaceWithWorkflow { */ val lhs = callFromName(ast.getAttribute("lhs") match { case a: Ast => WdlExpression.toString(a) - case terminal: Terminal => terminal.sourceString() + case terminal: Terminal => terminal.sourceString }) lhs match { - case Success(c:Call) => + case Success(c: Call) => c.task.outputs.find {_.name == rhs}.getOrElse { throw new SyntaxError(wdlSyntaxErrorFormatter.memberAccessReferencesBadTaskInput(ast)) } diff --git a/src/main/scala/cromwell/binding/WdlStandardLibraryFunctions.scala b/src/main/scala/cromwell/binding/WdlStandardLibraryFunctions.scala new file mode 100644 index 00000000000..330c7616cf7 --- /dev/null +++ b/src/main/scala/cromwell/binding/WdlStandardLibraryFunctions.scala @@ -0,0 +1,45 @@ +package cromwell.binding + +import cromwell.binding.values._ + +import scala.util.{Failure, Try} + +trait WdlStandardLibraryFunctions extends WdlFunctions { + private def fail(name: String) = Failure(new UnsupportedOperationException(s"$name() not implemented yet")) + + protected def stdout(params: Seq[Try[WdlValue]]): Try[WdlFile] = fail("stdout") + protected def stderr(params: Seq[Try[WdlValue]]): Try[WdlFile] = fail("stderr") + protected def read_lines(params: Seq[Try[WdlValue]]): Try[WdlArray] = fail("read_lines") + protected def read_tsv(params: Seq[Try[WdlValue]]): Try[WdlArray] = fail("read_tsv") + protected def read_map(params: Seq[Try[WdlValue]]): Try[WdlMap] = fail("read_map") + protected def read_object(params: Seq[Try[WdlValue]]): Try[WdlObject] = fail("read_objects") + protected def read_objects(params: Seq[Try[WdlValue]]): Try[WdlArray] = fail("read_objects") + protected def read_json(params: Seq[Try[WdlValue]]): Try[WdlValue] = fail("read_json") + protected def read_int(params: Seq[Try[WdlValue]]): Try[WdlInteger] = fail("read_int") + protected def read_string(params: Seq[Try[WdlValue]]): Try[WdlString] = fail("read_string") + protected def read_float(params: Seq[Try[WdlValue]]): Try[WdlFloat] = fail("read_float") + protected def read_boolean(params: Seq[Try[WdlValue]]): Try[WdlBoolean] = fail("read_boolean") + protected def write_lines(params: Seq[Try[WdlValue]]): Try[WdlFile] = fail("write_lines") + protected def write_tsv(params: Seq[Try[WdlValue]]): Try[WdlFile] = fail("write_tsv") + protected def write_map(params: Seq[Try[WdlValue]]): Try[WdlFile] = fail("write_map") + protected def write_object(params: Seq[Try[WdlValue]]): Try[WdlFile] = fail("write_object") + protected def write_objects(params: Seq[Try[WdlValue]]): Try[WdlFile] = fail("write_objects") + protected def write_json(params: Seq[Try[WdlValue]]): Try[WdlFile] = fail("write_json") + + /** + * Extract a single `WdlValue` from the specified `Seq`, returning `Failure` if the parameters + * represent something other than a single `WdlValue`. + */ + protected def extractSingleArgument(params: Seq[Try[WdlValue]]): Try[WdlValue] = { + if (params.length != 1) Failure(new UnsupportedOperationException("Expected one argument, got " + params.length)) + else params.head + } + + /* Returns one of the standard library functions (defined above) by name */ + def getFunction(name: String): WdlFunction = { + val method = getClass.getMethod(name, classOf[Seq[Try[WdlValue]]]) + args => method.invoke(this, args).asInstanceOf[Try[WdlValue]] + } +} + +class NoFunctions extends WdlStandardLibraryFunctions diff --git a/src/main/scala/cromwell/binding/WdlSyntaxErrorFormatter.scala b/src/main/scala/cromwell/binding/WdlSyntaxErrorFormatter.scala index 554de9b8186..2e19fa5cb42 100644 --- a/src/main/scala/cromwell/binding/WdlSyntaxErrorFormatter.scala +++ b/src/main/scala/cromwell/binding/WdlSyntaxErrorFormatter.scala @@ -176,40 +176,17 @@ case class WdlSyntaxErrorFormatter(terminalMap: Map[Terminal, WdlSource]) extend """.stripMargin } - def arrayMustHaveATypeParameter(arrayDecl: Terminal): String = { - s"""ERROR: Array type should have exactly one parameterized type (line ${arrayDecl.getLine}, col ${arrayDecl.getColumn}): + def mapMustHaveExactlyTwoTypeParameters(mapDecl: Terminal): String = { + s"""ERROR: Map type should have two parameterized types (line ${mapDecl.getLine}, col ${mapDecl.getColumn}): | - |${pointToSource(arrayDecl)} - """.stripMargin - } - - def postfixQualifierRequiresSeparator(quantifier: Terminal) = { - s"""ERROR: Parameters that specify * or + must also specify sep="" - | - |${pointToSource(quantifier)} - """.stripMargin - } - - def defaultAttributeOnlyAllowedForOptionalParameters(location: Terminal) = { - s"""ERROR: the 'default' attribute is only allowed with optional parameters (suffixed by either ? or *) - | - |${pointToSource(location)} + |${pointToSource(mapDecl)} """.stripMargin } - def parametersWithSameNameMustHaveSameDefinition(taskName: Terminal, firstParam: Terminal, secondParam: Terminal) = { - s"""ERROR: Task ${taskName.getSourceString} has input '${firstParam.getSourceString}' which is defined twice - |with conficting definitions: - | - |${pointToSource(secondParam)} - | - |first definition of parameter is here: - | - |${pointToSource(firstParam)} - | - |Task defined here (line ${taskName.getLine}, col ${taskName.getColumn}): - | - |${pointToSource(taskName)} + def arrayMustHaveATypeParameter(arrayDecl: Terminal): String = { + s"""ERROR: Array type should have exactly one parameterized type (line ${arrayDecl.getLine}, col ${arrayDecl.getColumn}): + | + |${pointToSource(arrayDecl)} """.stripMargin } } diff --git a/src/main/scala/cromwell/binding/Workflow.scala b/src/main/scala/cromwell/binding/Workflow.scala index c62f4f99578..7ed30c669b0 100644 --- a/src/main/scala/cromwell/binding/Workflow.scala +++ b/src/main/scala/cromwell/binding/Workflow.scala @@ -2,22 +2,29 @@ package cromwell.binding import cromwell.binding.AstTools.{AstNodeName, EnhancedAstNode} import cromwell.binding.types.WdlType -import cromwell.parser.WdlParser.{SyntaxError, Ast, Terminal} +import cromwell.parser.WdlParser.{Ast, SyntaxError, Terminal} + object Workflow { - def apply(ast: Ast, wdlSyntaxErrorFormatter: WdlSyntaxErrorFormatter, calls: Seq[Call]): Workflow = { + + def apply(ast: Ast, wdlSyntaxErrorFormatter: WdlSyntaxErrorFormatter, parent: Option[Scope]): Workflow = { val name = ast.getAttribute("name").asInstanceOf[Terminal].getSourceString val declarations = ast.findAsts(AstNodeName.Declaration).map(Declaration(_, name, wdlSyntaxErrorFormatter)) val callNames = ast.findAsts(AstNodeName.Call).map {call => Option(call.getAttribute("alias")).getOrElse(call.getAttribute("task")) } + val workflowOutputsDecls = ast.findAsts(AstNodeName.WorkflowOutput) map { wfOutput => + val wildcard = Option(wfOutput.getAttribute("wildcard")).map(_.sourceString).getOrElse("").nonEmpty + WorkflowOutputDeclaration(wfOutput.getAttribute("fqn").sourceString, wildcard) + } - callNames.groupBy {_.sourceString()}.foreach { - case (name, terminals) if terminals.size > 1 => + callNames groupBy { _.sourceString } foreach { + case (_, terminals) if terminals.size > 1 => throw new SyntaxError(wdlSyntaxErrorFormatter.multipleCallsAndHaveSameName(terminals.asInstanceOf[Seq[Terminal]])) case _ => } - new Workflow(name, declarations, calls) + + new Workflow(name, declarations, parent, workflowOutputsDecls) } } @@ -27,15 +34,15 @@ object Workflow { * the workflow * * @param name The name of the workflow - * @param calls The set of `call` declarations */ -case class Workflow(name: String, declarations: Seq[Declaration], calls: Seq[Call]) extends Executable with Scope { - calls foreach {c => c.setParent(this)} +case class Workflow(name: String, declarations: Seq[Declaration], parent: Option[Scope], workflowOutputDecls: Seq[WorkflowOutputDeclaration]) extends Executable with Scope { - /** Parent node for this workflow. Since we do not support nested - * workflows currently, this is always `None` - */ - val parent: Option[Scope] = None + /* Calls and scatters are accessed frequently so this avoids traversing the whole children tree every time. + * Lazy because children are not provided at instantiation but rather later during tree building process. + * This prevents evaluation from being done before children have been set. + * */ + lazy val calls: Seq[Call] = collectAllCalls + lazy val scatters: Seq[Scatter] = collectAllScatters /** * All inputs for this workflow and their associated types. @@ -44,8 +51,8 @@ case class Workflow(name: String, declarations: Seq[Declaration], calls: Seq[Cal * inputs that the user needs to provide to this workflow */ def inputs: Seq[WorkflowInput] = { - val callInputs = for {call <- calls; input <- call.unsatisfiedInputs} yield input - val declarationInputs = for(declaration <- declarations; input <- declaration.asWorkflowInput) yield input + val callInputs = for { call <- calls; input <- call.unsatisfiedInputs } yield input + val declarationInputs = for { declaration <- declarations; input <- declaration.asWorkflowInput } yield input callInputs ++ declarationInputs } diff --git a/src/main/scala/cromwell/binding/WorkflowInput.scala b/src/main/scala/cromwell/binding/WorkflowInput.scala index 46518b66208..f8f5632c367 100644 --- a/src/main/scala/cromwell/binding/WorkflowInput.scala +++ b/src/main/scala/cromwell/binding/WorkflowInput.scala @@ -1,11 +1,10 @@ package cromwell.binding -import cromwell.binding.command.ParameterCommandPart import cromwell.binding.types.WdlType case class WorkflowInput(fqn: FullyQualifiedName, wdlType: WdlType, postfixQuantifier: Option[String]) { val optional = postfixQuantifier match { - case Some(s) => ParameterCommandPart.OptionalPostfixQuantifiers.contains(s) + case Some(s) if s == "?" => true case _ => false } } diff --git a/src/main/scala/cromwell/binding/WorkflowOutputDeclaration.scala b/src/main/scala/cromwell/binding/WorkflowOutputDeclaration.scala new file mode 100644 index 00000000000..a705cf2e4df --- /dev/null +++ b/src/main/scala/cromwell/binding/WorkflowOutputDeclaration.scala @@ -0,0 +1,3 @@ +package cromwell.binding + +case class WorkflowOutputDeclaration(fqn: String, wildcard: Boolean) diff --git a/src/main/scala/cromwell/binding/command/Command.scala b/src/main/scala/cromwell/binding/command/Command.scala deleted file mode 100644 index c030702edc8..00000000000 --- a/src/main/scala/cromwell/binding/command/Command.scala +++ /dev/null @@ -1,160 +0,0 @@ -package cromwell.binding.command - -import java.util.regex.Pattern - -import cromwell.binding.{WdlSyntaxErrorFormatter, CallInputs, TaskInput} -import cromwell.binding.types.WdlArrayType -import cromwell.parser.WdlParser.{Ast, AstList, Terminal} - -import scala.annotation.tailrec -import scala.collection.JavaConverters._ -import scala.util.Try - -object Command { - def apply(ast: Ast, wdlSyntaxErrorFormatter: WdlSyntaxErrorFormatter): Command = { - val parts = ast.getAttribute("parts").asInstanceOf[AstList].asScala.toVector.map { - case x: Terminal => new StringCommandPart(x.getSourceString) - case x: Ast => ParameterCommandPart(x, wdlSyntaxErrorFormatter) - } - - new Command(parts) - } -} - -/** - * Represents the `command` section of a `task` definition in a WDL file. - * - * A command is a sequence of CommandPart objects which can either be String - * literals or parameters that the user needs to provide. For example, consider - * the following command: - * - * grep '${pattern}' ${file in} - * - * The Seq[CommandPart] would look as follows: - * - *
    - *
  1. StringCommandPart:
    grep '
  2. - *
  3. ParameterCommandPart: pattern (type=string)
  4. - *
  5. StringCommandPart:
    ' 
  6. - *
  7. ParameterCommandPart: in (type=file)
  8. - *
- * - * The result of the `inputs` method would be - * - *
    - *
  1. (
    pattern
    ,
    string
    )
  2. - *
  3. (
    in
    ,
    file
    )
  4. - *
- * - * A command line can be "instantiated" via the instantiate() method by providing a - * value for all of its inputs. The result is a string representation of the command - * - * @param parts The CommandParts that represent this command line - */ -case class Command(parts: Seq[CommandPart]) { - val ws = Pattern.compile("[\\ \\t]+") - def inputs: Seq[TaskInput] = { - val collectedInputs = parts.collect {case p: ParameterCommandPart => p}.map {p => - // TODO: if postfix quantifier is + or *, then the type must be a primitive. - val wdlType = p.postfixQuantifier match { - case Some(x) if ParameterCommandPart.PostfixQuantifiersThatAcceptArrays.contains(x) => WdlArrayType(p.wdlType) - case _ => p.wdlType - } - TaskInput(p.name, wdlType, p.postfixQuantifier) - } - - /* It is assumed here that all TaskInputs with the same name are identically defined, this filters out duplicates by name */ - collectedInputs.map {_.name}.distinct.map {name => - collectedInputs.filter {_.name == name}.head - } - } - - /** - * Given a map of task-local parameter names and WdlValues, - * create a command String. - * - * Instantiating a command line is the process of taking a command in this form: - * - * {{{ - * sh script.sh ${var1} -o ${var2} - * }}} - * - * This command is stored as a `Seq[CommandPart]` in the `Command` class (e.g. [sh script.sh, ${var1}, -o, ${var2}]). - * Then, given a map of variable -> value: - * - * {{{ - * { - * "var1": "foo", - * "var2": "bar" - * } - * }}} - * - * It calls instantiate() on each part, and passes this map. The ParameterCommandPart are the ${var1} and ${var2} - * pieces and they lookup var1 and var2 in that map. - * - * The command that's returned from Command.instantiate() is: - * - * - * {{{sh script.sh foo -o bar}}} - * - * @param parameters Parameter values - * @return String instantiation of the command - */ - def instantiate(parameters: CallInputs): Try[String] = { - Try(normalize(parts.map { _.instantiate(parameters) }.mkString(""))) - } - - /** - * 1) Remove all leading newline chars - * 2) Remove all trailing newline AND whitespace chars - * 3) Remove all *leading* whitespace that's common among every line in the input string - * - * For example, the input string: - * - * " - * first line - * second line - * third line - * - * " - * - * Would be normalized to: - * - * "first line - * second line - * third line" - * - * @param s String to process - * @return String which has common leading whitespace removed from each line - */ - def normalize(s: String): String = { - val trimmed = stripAll(s, "\r\n", "\r\n \t") - val parts = trimmed.split("[\\r\\n]+") - val indent = parts.map(leadingWhitespaceCount).min - parts.map(_.substring(indent)).mkString("\n") - } - - private def leadingWhitespaceCount(s: String): Int = { - val matcher = ws.matcher(s) - if (matcher.lookingAt) matcher.end else 0 - } - - private def stripAll(s: String, startChars: String, endChars: String): String = { - /* https://stackoverflow.com/questions/17995260/trimming-strings-in-scala */ - @tailrec - def start(n: Int): String = { - if (n == s.length) "" - else if (startChars.indexOf(s.charAt(n)) < 0) end(n, s.length) - else start(1 + n) - } - @tailrec - def end(a: Int, n: Int): String = { - if (n <= a) s.substring(a, n) - else if (endChars.indexOf(s.charAt(n - 1)) < 0) s.substring(a, n) - else end(a, n - 1) - } - start(0) - } - - override def toString: String = s"[Command: ${normalize(parts.map(y => y.toString).mkString(""))}]" -} diff --git a/src/main/scala/cromwell/binding/command/CommandPart.scala b/src/main/scala/cromwell/binding/command/CommandPart.scala index 0a9dd15fa1b..8343c0aa46a 100644 --- a/src/main/scala/cromwell/binding/command/CommandPart.scala +++ b/src/main/scala/cromwell/binding/command/CommandPart.scala @@ -1,7 +1,8 @@ package cromwell.binding.command import cromwell.binding.values.WdlValue +import cromwell.binding.{Declaration, WdlFunctions} trait CommandPart { - def instantiate(parameters: Map[String, WdlValue]): String + def instantiate(declarations: Seq[Declaration], parameters: Map[String, WdlValue], functions: WdlFunctions): String } diff --git a/src/main/scala/cromwell/binding/command/ParameterCommandPart.scala b/src/main/scala/cromwell/binding/command/ParameterCommandPart.scala index 5eb30a7449c..61d90b9b562 100644 --- a/src/main/scala/cromwell/binding/command/ParameterCommandPart.scala +++ b/src/main/scala/cromwell/binding/command/ParameterCommandPart.scala @@ -1,105 +1,49 @@ package cromwell.binding.command import cromwell.binding.AstTools.EnhancedAstNode -import cromwell.binding.types.WdlType +import cromwell.binding._ import cromwell.binding.values.{WdlArray, WdlPrimitive, WdlString, WdlValue} -import cromwell.binding.{AstTools, WdlExpression, WdlSyntaxErrorFormatter} -import cromwell.parser.WdlParser.{Ast, AstList, SyntaxError, Terminal} +import cromwell.parser.WdlParser.Ast -import scala.collection.JavaConverters._ +import scala.util.{Failure, Success} object ParameterCommandPart { - val PostfixQuantifiersThatAcceptArrays = Set("+", "*") - val OptionalPostfixQuantifiers = Set("?", "*") - def apply(ast: Ast, wdlSyntaxErrorFormatter: WdlSyntaxErrorFormatter): ParameterCommandPart = { - val wdlType = ast.getAttribute("type").wdlType(wdlSyntaxErrorFormatter) - val name = ast.getAttribute("name").asInstanceOf[Terminal].getSourceString - val prefix = Option(ast.getAttribute("prefix")) map { case t:Terminal => t.sourceString() } - val attributes = ast.getAttribute("attributes").asInstanceOf[AstList].asScala.toSeq.map { a => + val attributes = ast.getAttribute("attributes").astListAsVector map { a => val ast = a.asInstanceOf[Ast] - (ast.getAttribute("key").sourceString(), ast.getAttribute("value").sourceString()) - }.toMap - val postfixQuantifier = ast.getAttribute("postfix") match { - case t:Terminal => Some(t.sourceString()) - case _ => None - } - postfixQuantifier.foreach {quantifier => - val postfixQuantifierToken = ast.getAttribute("postfix").asInstanceOf[Terminal] - if (PostfixQuantifiersThatAcceptArrays.contains(quantifier) && !attributes.contains("sep")) - throw new SyntaxError(wdlSyntaxErrorFormatter.postfixQualifierRequiresSeparator(postfixQuantifierToken)) - if (!OptionalPostfixQuantifiers.contains(quantifier) && attributes.contains("default")) - throw new SyntaxError(wdlSyntaxErrorFormatter.defaultAttributeOnlyAllowedForOptionalParameters(postfixQuantifierToken)) - } - if (attributes.contains("default") && postfixQuantifier.isEmpty) { - /* Calling .get below because we're assuming if attribute.contains("default"), then this operation is safe */ - val declarationOfDefaultAttribute = ast.getAttribute("attributes").asInstanceOf[AstList].asScala.toSeq.find{node => - node.asInstanceOf[Ast].getAttribute("key").asInstanceOf[Terminal].getSourceString == "default" - }.get - val terminal = declarationOfDefaultAttribute.asInstanceOf[Ast].getAttribute("key").asInstanceOf[Terminal] - throw new SyntaxError(wdlSyntaxErrorFormatter.defaultAttributeOnlyAllowedForOptionalParameters(terminal)) + (ast.getAttribute("key").sourceString, ast.getAttribute("value").sourceString) } - new ParameterCommandPart(wdlType, name, prefix, attributes, postfixQuantifier) + val expression = WdlExpression(ast.getAttribute("expr")) + new ParameterCommandPart(attributes.toMap, expression) } } -/** - * Represents a parameter within a command, e.g. `${default="/etc/foo.conf" "--conf=" File conf?}` - * - * @param wdlType - The type that the input is required to be (`File`) - * @param name - The name of the parameter (`conf`) - * @param prefix - Optional prefix for when the parameter is specified. This will be prepended to the parameter (`--conf=`) - * @param attributes - A set of key (String) -> value (String) pairs from x="y" pairs within the parameter (default -> /etc/foo.conf) - * There are only a subset of these attributes that have any meaning. `default` is interpreted to be - * the default value of the variable `conf` if no value is specified (since it's optional) - * @param postfixQuantifier - The `?`, `*`, or `+` after the variable name. This means "optional", "0-or-more", and "1-or-more", respectively - */ -case class ParameterCommandPart(wdlType: WdlType, name: String, - prefix: Option[String], attributes: Map[String, String], - postfixQuantifier: Option[String] = None) extends CommandPart { - override def toString: String = "${" + s"${wdlType.toWdlString} $name" + "}" - - def instantiate(parameters: Map[String, WdlValue]): String = { - def wasDefaultValueUsed: Boolean = parameters.get(name).isEmpty && attributes.contains("default") - - /* Order DOES matter in this match clause */ - val paramValue = parameters.get(name) match { - case Some(value) => value - case None if attributes.contains("default") => WdlString(attributes.get("default").get) - case None if postfixQuantifier.isDefined && ParameterCommandPart.OptionalPostfixQuantifiers.contains(postfixQuantifier.head) => WdlString("") - case _ => throw new UnsupportedOperationException(s"Parameter $name not found") - } - val paramValueEvaluated = paramValue match { - case e: WdlExpression => - /* TODO: this should never happen because expressions will be evaluated - before this method is called. The reason why we can't always do it - here is because unless scope information is stored in the WdlExpression - itself (along with lookup and WdlFunctions objects), we'd have no way to - evaluate this with any reasonable variable dereferencing. - */ - throw new UnsupportedOperationException("All WdlExpressions must be evaluated before calling this") - case x => x - } - - if (!wasDefaultValueUsed && postfixQuantifier.isEmpty && wdlType != paramValueEvaluated.wdlType) { - throw new UnsupportedOperationException(s"Incompatible type for $name: need a $wdlType, got a ${paramValue.wdlType}") +case class ParameterCommandPart(attributes: Map[String, String], expression: WdlExpression) extends CommandPart { + def attributesToString: String = if (attributes.nonEmpty) attributes.map({case (k,v) => s"$k='$v'"}).mkString(", ") + " " else "" + override def toString: String = "${" + s"$attributesToString${expression.toWdlString}" + "}" + + override def instantiate(declarations: Seq[Declaration], parameters: Map[String, WdlValue], functions: WdlFunctions = new NoFunctions): String = { + case class VariableNotFoundException(variable: String) extends RuntimeException(s"Could not find variable: $variable") + def lookup(key: String) = parameters.getOrElse(key, throw new VariableNotFoundException(key)) + + val value = expression.evaluate(lookup, functions) match { + case Success(v) => v + case Failure(f) => f match { + case v: VariableNotFoundException => declarations.find(_.name == v.variable) match { + /* Allow an expression to fail evaluation if one of the variables that it requires is optional (the type has ? after it, e.g. String?) */ + case Some(d) if d.postfixQuantifier.contains("?") => if (attributes.contains("default")) WdlString(attributes.get("default").head) else WdlString("") + case Some(d) => throw new UnsupportedOperationException(s"Parameter ${v.variable} is required, but no value is specified") + case None => throw new UnsupportedOperationException(s"This should not happen: could not find declaration for ${v.variable}") + } + case _ => throw new UnsupportedOperationException(s"Could not evaluate expression: ${expression.toString}") + } } - /* TODO: asString should be deprecated in the near future - * It is being used as here because primitive types are trivially - * turned into strings, but a more sophisticated solution will be - * needed for compound types */ - paramValueEvaluated match { - case WdlString("") => "" - case param:WdlPrimitive => s"${prefix.getOrElse("")}${param.valueString}" - case arr:WdlArray => - postfixQuantifier match { - case Some(x) if ParameterCommandPart.PostfixQuantifiersThatAcceptArrays.contains(x) && attributes.contains("sep") => - val concatValue = arr.value.map {_.valueString}.mkString(attributes.get("sep").head) - s"${prefix.getOrElse("")}$concatValue" - case _ => throw new UnsupportedOperationException() - } - case _ => throw new UnsupportedOperationException("Not implemented yet") + value match { + case p: WdlPrimitive => p.valueString + case a: WdlArray if attributes.contains("sep") => a.value.map(_.valueString).mkString(attributes.get("sep").head) + case a: WdlArray => throw new UnsupportedOperationException(s"Expression '${expression.toString}' evaluated to an Array but no 'sep' was specified") + case _ => throw new UnsupportedOperationException(s"Could not string-ify value: $value") } } } diff --git a/src/main/scala/cromwell/binding/command/StringCommandPart.scala b/src/main/scala/cromwell/binding/command/StringCommandPart.scala index da32ae13262..323ab26f18c 100644 --- a/src/main/scala/cromwell/binding/command/StringCommandPart.scala +++ b/src/main/scala/cromwell/binding/command/StringCommandPart.scala @@ -1,9 +1,10 @@ package cromwell.binding.command import cromwell.binding.values.WdlValue +import cromwell.binding.{Declaration, WdlFunctions} case class StringCommandPart(literal: String) extends CommandPart { override def toString: String = literal - def instantiate(parameters: Map[String, WdlValue]): String = literal + override def instantiate(declarations: Seq[Declaration], parameters: Map[String, WdlValue], functions: WdlFunctions): String = literal } diff --git a/src/main/scala/cromwell/binding/formatter/SyntaxFormatter.scala b/src/main/scala/cromwell/binding/formatter/SyntaxFormatter.scala index 1a9908d0c17..dc851df77d9 100644 --- a/src/main/scala/cromwell/binding/formatter/SyntaxFormatter.scala +++ b/src/main/scala/cromwell/binding/formatter/SyntaxFormatter.scala @@ -1,10 +1,10 @@ package cromwell.binding.formatter +import cromwell.binding.AstTools.EnhancedAstNode import cromwell.binding._ -import cromwell.binding.command.{Command, ParameterCommandPart, StringCommandPart} +import cromwell.binding.command.StringCommandPart import cromwell.binding.types.WdlType -import cromwell.binding.AstTools.EnhancedAstNode -import cromwell.parser.WdlParser.{Ast, AstList, AstNode, Terminal} +import cromwell.parser.WdlParser.{Ast, AstList, AstNode} import cromwell.util.TerminalUtil import scala.collection.JavaConverters._ @@ -25,7 +25,7 @@ object NullSyntaxHighlighter extends SyntaxHighlighter object AnsiSyntaxHighlighter extends SyntaxHighlighter { override def keyword(s: String): String = TerminalUtil.highlight(214, s) override def name(s: String): String = TerminalUtil.highlight(253, s) - override def section(s: String): String = s + override def section(s: String): String = keyword(s) override def wdlType(t: WdlType): String = TerminalUtil.highlight(33, t.toWdlString) override def variable(s: String): String = TerminalUtil.highlight(112, s) override def alias(s: String): String = s @@ -66,7 +66,7 @@ class SyntaxFormatter(highlighter: SyntaxHighlighter = NullSyntaxHighlighter) { val namespaceDefinitions = namespace.ast.getAttribute("definitions").asInstanceOf[AstList].asScala.toVector val taskDefinitions = namespaceDefinitions collect { case a: Ast if a.getName == "Task" => - formatTask(namespace.findTask(a.getAttribute("name").sourceString()).getOrElse(throw new UnsupportedOperationException("Shouldn't happen"))) + formatTask(namespace.findTask(a.getAttribute("name").sourceString).getOrElse(throw new UnsupportedOperationException("Shouldn't happen"))) } val workflowDefinitions = namespace match { @@ -85,8 +85,12 @@ class SyntaxFormatter(highlighter: SyntaxHighlighter = NullSyntaxHighlighter) { private def formatTask(task: Task): String = { val outputs = if (task.outputs.nonEmpty) formatOutputs(task.outputs, 1) else "" - val command = formatCommandSection(task.command, 1) - val sections = List(command, outputs).filter(_.nonEmpty) + val command = formatCommandSection(task, 1) + val declarations = task.declarations.map(formatDeclaration(_, 1)) match { + case x: Seq[String] if x.nonEmpty => x.mkString("\n") + case _ => "" + } + val sections = List(declarations, command, outputs).filter(_.nonEmpty) val header = s"""${highlighter.keyword("task")} ${highlighter.name(task.name)} { |${sections.mkString("\n")} |}""" @@ -94,31 +98,15 @@ class SyntaxFormatter(highlighter: SyntaxHighlighter = NullSyntaxHighlighter) { header } - private def formatCommandSection(command: Command, level:Int): String = { - val section = s"""${highlighter.section("command")} { - |${formatCommand(command, level+1)} - |}""" - indent(section.stripMargin, level) - } - - private def formatCommand(command: Command, level:Int): String = { - val abstractCommand = command.parts.map { - case x:StringCommandPart => x - case x:ParameterCommandPart => formatParameterCommandPart(x) - } - indent(highlighter.command(command.normalize(abstractCommand.mkString)), 1) - } + private def formatCommandSection(task: Task, level:Int): String = { + val (sdelim: String, edelim: String) = + if (task.commandTemplate.collect({case s:StringCommandPart => s.literal}).mkString.contains("}")) ("<<<", ">>>") + else ("{", "}") - private def formatParameterCommandPart(cmdPart: ParameterCommandPart): String = { - val attributes = cmdPart.attributes.map{case (k,v) => s"$k='$v'"} match { - case i: Iterable[String] if i.isEmpty => "" - case i: Iterable[String] => s"${i.mkString(" ")} " - } - val prefix = cmdPart.prefix.map {str => s"'$str' "}.getOrElse("") - val wdlType = highlighter.wdlType(cmdPart.wdlType) - val postfixQuantifier = cmdPart.postfixQuantifier.getOrElse("") - val variableName = highlighter.variable(cmdPart.name) - s"$${$attributes$prefix$wdlType $variableName$postfixQuantifier}" + val section = s"""${highlighter.section("command")} $sdelim + |${indent(highlighter.command(task.commandTemplateString), 1)} + |$edelim""" + indent(section.stripMargin, level) } private def formatOutputs(outputs: Seq[TaskOutput], level:Int): String = { @@ -133,18 +121,17 @@ class SyntaxFormatter(highlighter: SyntaxHighlighter = NullSyntaxHighlighter) { } private def formatWorkflow(workflow: Workflow): String = { - val declarations = workflow.declarations.map{formatDeclaration(_, 1)} match { - case x: Seq[String] if !x.isEmpty => s"\n${x.mkString("\n")}\n" - case _ => "" - } - s"""${highlighter.keyword("workflow")} ${highlighter.name(workflow.name)} {$declarations - |${workflow.calls.map{formatCall(_, 1)}.mkString("\n")} + val declarations = workflow.declarations.map(formatDeclaration(_, 1)) + val calls = workflow.calls.map(formatCall(_, 1)) + val sections = (declarations ++ calls).filter(_.nonEmpty) + s"""${highlighter.keyword("workflow")} ${highlighter.name(workflow.name)} { + |${sections.mkString("\n")} |}""".stripMargin } private def formatDeclaration(decl: Declaration, level: Int): String = { - val expression = decl.expression.map {e => s" = ${e.toWdlString}"}.getOrElse("") - indent(s"${highlighter.wdlType(decl.wdlType)} ${highlighter.name(decl.name)}$expression", level) + val expression = decl.expression.map(e => s" = ${e.toWdlString}").getOrElse("") + indent(s"${highlighter.wdlType(decl.wdlType)} ${highlighter.variable(decl.name)}$expression", level) } private def formatCall(call: Call, level:Int): String = { diff --git a/src/main/scala/cromwell/binding/package.scala b/src/main/scala/cromwell/binding/package.scala index d6aa3455a3c..91aa20fd9d6 100644 --- a/src/main/scala/cromwell/binding/package.scala +++ b/src/main/scala/cromwell/binding/package.scala @@ -1,8 +1,7 @@ package cromwell -import java.util.UUID - import cromwell.binding.values.WdlValue +import cromwell.engine.WorkflowId /** * ==WDL Bindings for Scala== @@ -31,7 +30,7 @@ package object binding { /** * Core data identifying a workflow including its unique ID, its namespace, and strongly typed inputs. */ - case class WorkflowDescriptor(id: UUID, namespace: NamespaceWithWorkflow, wdlSource: WdlSource, wdlJson: WdlJson, actualInputs: WorkflowCoercedInputs) { + case class WorkflowDescriptor(id: WorkflowId, namespace: NamespaceWithWorkflow, wdlSource: WdlSource, wdlJson: WdlJson, actualInputs: WorkflowCoercedInputs) { val name = namespace.workflow.name val shortId = id.toString.split("-")(0) } diff --git a/src/main/scala/cromwell/binding/types/WdlAnyType.scala b/src/main/scala/cromwell/binding/types/WdlAnyType.scala new file mode 100644 index 00000000000..dd6f84e59e0 --- /dev/null +++ b/src/main/scala/cromwell/binding/types/WdlAnyType.scala @@ -0,0 +1,47 @@ +package cromwell.binding.types + +case object WdlAnyType extends WdlType { + val toWdlString: String = s"Any" + + /** + * WdlAnyType does behave slightly differently than the other WdlTypes. + * For something like WdlInteger, the coercion function acts as follows: + * + * "Give me one of x different type of objects that are compatible with + * WdlInteger, and I'll give you a WdlInteger back" + * + * WdlAnyType's coercion semantics are more like: + * + * "Give me anything at all, and I've got a heuristic that will return you + * the WdlValue that's able to accept this Any value." + * + * So you give this coercion() function a String "foobar", and it returns + * WdlString("foobar"), you give it a JsNumber(2), it returns WdlInteger(2). + * + * This is used when evaluating literal expressions. For example, a user + * might do this in source code: + * + *
+   * Map[Int, String] first = {"foo": 2, 3.14: "bar"}
+   * Map[Float, String] second = {"foo": "bar"}
+   * 
+ * + * When we're simply parsing the expression {"foo": 2, 3.14: "bar"}, there + * are two levels of coercion happening. First it just tries to coerce this + * into ANY Map[K, V] type. It uses Map[Any, Any].coerce for that. The first + * example above would fail this coercion stage. The second would pass and + * return a Map[String, String]. + * + * The second coercion that happens is the coercion to the target type. + * In the example above, second starts out coerced as Map[String, String], + * and then it is Map[Float, String].coerce is called on that map. This step + * should fail at this stage. + */ + override protected def coercion = { + case any: Any => + /* This does throw an exception if it couldn't coerce (.get is intentional) */ + WdlType.wdlTypeCoercionOrder.map(_.coerceRawValue(any)).find(_.isSuccess).getOrElse( + throw new UnsupportedOperationException(s"Could not coerce $any into a WDL type") + ).get + } +} diff --git a/src/main/scala/cromwell/binding/types/WdlArrayType.scala b/src/main/scala/cromwell/binding/types/WdlArrayType.scala index e5d524cb1a1..fd5263f99ff 100644 --- a/src/main/scala/cromwell/binding/types/WdlArrayType.scala +++ b/src/main/scala/cromwell/binding/types/WdlArrayType.scala @@ -1,6 +1,6 @@ package cromwell.binding.types -import cromwell.binding.values.{WdlFile, WdlString, WdlArray} +import cromwell.binding.values.{WdlArray, WdlFile, WdlString} import spray.json.JsArray case class WdlArrayType(memberType: WdlType) extends WdlType { @@ -13,6 +13,7 @@ case class WdlArrayType(memberType: WdlType) extends WdlType { override protected def coercion = { case s: Seq[Any] if s.nonEmpty => coerceIterable(s) + case s: Seq[Any] if s.isEmpty => WdlArray(WdlArrayType(memberType), Seq()) case js: JsArray if js.elements.nonEmpty => coerceIterable(js.elements) case wdlArray: WdlArray => wdlArray.wdlType.memberType match { case WdlStringType if memberType == WdlFileType => diff --git a/src/main/scala/cromwell/binding/types/WdlFileType.scala b/src/main/scala/cromwell/binding/types/WdlFileType.scala index a514d66867b..e58529638da 100644 --- a/src/main/scala/cromwell/binding/types/WdlFileType.scala +++ b/src/main/scala/cromwell/binding/types/WdlFileType.scala @@ -1,6 +1,6 @@ package cromwell.binding.types -import cromwell.binding.values.WdlFile +import cromwell.binding.values.{WdlFile, WdlString} import spray.json.JsString case object WdlFileType extends WdlPrimitiveType { @@ -9,6 +9,7 @@ case object WdlFileType extends WdlPrimitiveType { override protected def coercion = { case s: String => WdlFile(s) case s: JsString => WdlFile(s.value) + case s: WdlString => WdlFile(s.valueString) case f: WdlFile => f } } diff --git a/src/main/scala/cromwell/binding/types/WdlFloatType.scala b/src/main/scala/cromwell/binding/types/WdlFloatType.scala index 493d88c206f..c3836f34c5b 100644 --- a/src/main/scala/cromwell/binding/types/WdlFloatType.scala +++ b/src/main/scala/cromwell/binding/types/WdlFloatType.scala @@ -1,7 +1,7 @@ package cromwell.binding.types -import cromwell.binding.values.WdlFloat -import spray.json.JsNumber +import cromwell.binding.values.{WdlFloat, WdlString} +import spray.json.{JsNumber, JsString} case object WdlFloatType extends WdlPrimitiveType { val toWdlString: String = "Float" @@ -10,6 +10,9 @@ case object WdlFloatType extends WdlPrimitiveType { case d: Double => WdlFloat(d) case n: JsNumber => WdlFloat(n.value.doubleValue()) case f: WdlFloat => f + case s: String => WdlFloat(s.toDouble) + case s: JsString => WdlFloat(s.value.toDouble) + case s: WdlString => WdlFloat(s.value.toDouble) } override def fromWdlString(rawString: String) = WdlFloat(rawString.toFloat) diff --git a/src/main/scala/cromwell/binding/types/WdlIntegerType.scala b/src/main/scala/cromwell/binding/types/WdlIntegerType.scala index c011e2b62f1..2bb5b005a3f 100644 --- a/src/main/scala/cromwell/binding/types/WdlIntegerType.scala +++ b/src/main/scala/cromwell/binding/types/WdlIntegerType.scala @@ -1,7 +1,7 @@ package cromwell.binding.types -import cromwell.binding.values.WdlInteger -import spray.json.JsNumber +import cromwell.binding.values.{WdlInteger, WdlString} +import spray.json.{JsNumber, JsString} case object WdlIntegerType extends WdlPrimitiveType { val toWdlString: String = "Int" @@ -10,6 +10,9 @@ case object WdlIntegerType extends WdlPrimitiveType { case i: Integer => WdlInteger(i) case n: JsNumber => WdlInteger(n.value.intValue()) case i: WdlInteger => i + case s: WdlString => WdlInteger(s.value.toInt) + case s: String => WdlInteger(s.toInt) + case s: JsString => WdlInteger(s.value.toInt) } override def fromWdlString(rawString: String) = WdlInteger(rawString.toInt) diff --git a/src/main/scala/cromwell/binding/types/WdlMapType.scala b/src/main/scala/cromwell/binding/types/WdlMapType.scala new file mode 100644 index 00000000000..3af0a047127 --- /dev/null +++ b/src/main/scala/cromwell/binding/types/WdlMapType.scala @@ -0,0 +1,15 @@ +package cromwell.binding.types + +import cromwell.binding.values._ +import spray.json.JsObject + +case class WdlMapType(keyType: WdlType, valueType: WdlType) extends WdlType { + val toWdlString: String = s"Map[${keyType.toWdlString}, ${valueType.toWdlString}]" + + override protected def coercion = { + case m: Map[_, _] if m.nonEmpty => WdlMap.coerceMap(m, this) + case m: Map[_, _] if m.isEmpty => WdlMap(WdlMapType(keyType, valueType), Map()) + case js: JsObject if js.fields.nonEmpty => WdlMap.coerceMap(js.fields, this) + case wdlMap: WdlMap => WdlMap.coerceMap(wdlMap.value, this) + } +} diff --git a/src/main/scala/cromwell/binding/types/WdlNamespaceType.scala b/src/main/scala/cromwell/binding/types/WdlNamespaceType.scala index 47fbd6e789b..907cd73d36b 100644 --- a/src/main/scala/cromwell/binding/types/WdlNamespaceType.scala +++ b/src/main/scala/cromwell/binding/types/WdlNamespaceType.scala @@ -1,7 +1,13 @@ package cromwell.binding.types +import cromwell.binding.WdlNamespace + case object WdlNamespaceType extends WdlType { override def toWdlString: String = "Namespace" - override protected def coercion = ??? + + override protected def coercion = { + case n: WdlNamespace => n + } + override def fromWdlString(rawString: String) = ??? } diff --git a/src/main/scala/cromwell/binding/types/WdlObjectType.scala b/src/main/scala/cromwell/binding/types/WdlObjectType.scala index 186a8745715..07176ab8e1f 100644 --- a/src/main/scala/cromwell/binding/types/WdlObjectType.scala +++ b/src/main/scala/cromwell/binding/types/WdlObjectType.scala @@ -1,9 +1,13 @@ package cromwell.binding.types +import cromwell.binding.values.WdlObject + case object WdlObjectType extends WdlType { val toWdlString: String = "Object" - override protected def coercion = ??? + override protected def coercion = { + case o: WdlObject => o + } override def fromWdlString(rawString: String) = ??? } diff --git a/src/main/scala/cromwell/binding/types/WdlType.scala b/src/main/scala/cromwell/binding/types/WdlType.scala index dad908597d2..009f14febe3 100644 --- a/src/main/scala/cromwell/binding/types/WdlType.scala +++ b/src/main/scala/cromwell/binding/types/WdlType.scala @@ -2,11 +2,13 @@ package cromwell.binding.types import cromwell.binding.AstTools.EnhancedAstNode import cromwell.binding.values.WdlValue -import cromwell.binding.{AstTools, WdlSource, WdlSyntaxErrorFormatter} +import cromwell.binding.{WdlSource, WdlSyntaxErrorFormatter} import cromwell.parser.WdlParser import scala.collection.JavaConverters._ -import scala.util.{Failure, Try} +import scala.util.{Failure, Success, Try} + +class WdlTypeException(message: String) extends RuntimeException(message) trait WdlType { @@ -24,10 +26,10 @@ trait WdlType { * a `WdlValue`. */ def coerceRawValue(any: Any): Try[WdlValue] = { - if (!coercion.isDefinedAt(any)) { - Failure(new IllegalArgumentException(s"No coercion defined from '$any' of type '${any.getClass}' to ${getClass.getSimpleName}.")) - } else { - Try(coercion(any)) + any match { + case v: WdlValue if v.wdlType == this => Success(v) + case a if !coercion.isDefinedAt(any) => Failure(new IllegalArgumentException(s"No coercion defined from '$any' of type '${any.getClass}' to ${getClass.getSimpleName}.")) + case _ => Try(coercion(any)) } } @@ -57,11 +59,21 @@ trait WdlType { object WdlType { val parser = new WdlParser() - private lazy val wdlTypes = Seq( - WdlBooleanType, WdlExpressionType, WdlFileType, WdlFloatType, - WdlIntegerType, WdlNamespaceType, WdlObjectType, WdlStringType + /* This is in the order of coercion from non-wdl types */ + val wdlTypeCoercionOrder: Seq[WdlType] = Seq( + WdlStringType, WdlIntegerType, WdlFloatType, WdlMapType(WdlAnyType, WdlAnyType), + WdlArrayType(WdlAnyType), WdlBooleanType, WdlObjectType ) + def homogeneousType(values: Iterable[WdlValue]): Try[WdlType] = { + values.map(_.wdlType).toSet match { + case s if s.isEmpty => Failure(new WdlTypeException(s"Can't have empty Array/Map declarations (can't infer type)")) + case s if s.size == 1 => Success(s.head) + case _ => Failure(new WdlTypeException("Arrays/Maps must have homogeneous types")) + } + } + + def fromWdlString(wdlString: String): WdlType = { wdlString match { case "Expression" => WdlExpressionType diff --git a/src/main/scala/cromwell/binding/values/WdlArray.scala b/src/main/scala/cromwell/binding/values/WdlArray.scala index 160ab931812..cb544caaa00 100644 --- a/src/main/scala/cromwell/binding/values/WdlArray.scala +++ b/src/main/scala/cromwell/binding/values/WdlArray.scala @@ -1,6 +1,8 @@ package cromwell.binding.values -import cromwell.binding.types.WdlArrayType +import cromwell.binding.types.{WdlArrayType, WdlPrimitiveType} + +import scala.util.{Failure, Success, Try} case class WdlArray(wdlType: WdlArrayType, value: Seq[WdlValue]) extends WdlValue { val typesUsedInValue = Set(value map {_.wdlType}: _*) @@ -19,4 +21,11 @@ case class WdlArray(wdlType: WdlArrayType, value: Seq[WdlValue]) extends WdlValu case _ => this } } + + def tsvSerialize: Try[String] = { + wdlType.memberType match { + case t: WdlPrimitiveType => Success(value.map(_.valueString).mkString("\n")) + case _ => Failure(new UnsupportedOperationException("Can only TSV serialize an Array[Primitive]")) + } + } } \ No newline at end of file diff --git a/src/main/scala/cromwell/binding/values/WdlFile.scala b/src/main/scala/cromwell/binding/values/WdlFile.scala index 1015fd05e46..3ad46927a0a 100644 --- a/src/main/scala/cromwell/binding/values/WdlFile.scala +++ b/src/main/scala/cromwell/binding/values/WdlFile.scala @@ -1,6 +1,6 @@ package cromwell.binding.values -import cromwell.binding.types.{WdlType, WdlFileType} +import cromwell.binding.types.{WdlFileType, WdlType} import scala.util.{Success, Try} diff --git a/src/main/scala/cromwell/binding/values/WdlFloat.scala b/src/main/scala/cromwell/binding/values/WdlFloat.scala index 9ab2ec1e2a0..1b7694f938d 100644 --- a/src/main/scala/cromwell/binding/values/WdlFloat.scala +++ b/src/main/scala/cromwell/binding/values/WdlFloat.scala @@ -3,7 +3,7 @@ package cromwell.binding.values import cromwell.binding.WdlExpressionException import cromwell.binding.types.WdlFloatType -import scala.util.{Try, Success, Failure} +import scala.util.{Failure, Success, Try} case class WdlFloat(value: Double) extends WdlPrimitive { val wdlType = WdlFloatType diff --git a/src/main/scala/cromwell/binding/values/WdlMap.scala b/src/main/scala/cromwell/binding/values/WdlMap.scala new file mode 100644 index 00000000000..ec37ec3804f --- /dev/null +++ b/src/main/scala/cromwell/binding/values/WdlMap.scala @@ -0,0 +1,64 @@ +package cromwell.binding.values + +import cromwell.binding.types.{WdlAnyType, WdlMapType, WdlPrimitiveType, WdlType} +import cromwell.util.{FileUtil, TryUtil} + +import scala.util.{Failure, Success, Try} + +object WdlMap { + def coerceMap(m: Map[_, _], wdlMapType: WdlMapType): WdlMap = { + val coerced = m map { case(k, v) => wdlMapType.keyType.coerceRawValue(k) -> wdlMapType.valueType.coerceRawValue(v) } + val failures = coerced flatMap { case(k,v) => Seq(k,v) } collect { case f:Failure[_] => f } + failures match { + case f: Iterable[Failure[_]] if f.nonEmpty => + throw new UnsupportedOperationException(s"Failed to coerce one or more keys or values for creating a ${wdlMapType.toWdlString}:\n${TryUtil.stringifyFailures(f)}}") + case _ => + val mapCoerced = coerced map { case (k, v) => k.get -> v.get } + + // Yes, throw an exception if keyType or valueType can't be determined + val keyType = WdlType.homogeneousType(mapCoerced map { case (k, v) => k }).get + val valueType = WdlType.homogeneousType(mapCoerced map { case (k, v) => v }).get + + WdlMap(WdlMapType(keyType, valueType), mapCoerced) + } + } + + def fromTsv(tsv: String, wdlMapType: WdlMapType = WdlMapType(WdlAnyType, WdlAnyType)): Try[WdlMap] = { + FileUtil.parseTsv(tsv) match { + case Success(table) if table.isEmpty => Success(WdlMap(wdlMapType, Map.empty[WdlValue, WdlValue])) + case Success(table) if table.head.length != 2 => Failure(new UnsupportedOperationException("TSV must be 2 columns to convert to a Map")) + case Success(table) => Try(coerceMap(table.map(row => row(0) -> row(1)).toMap, wdlMapType)) + case Failure(e) => Failure(e) + } + } +} + +case class WdlMap(wdlType: WdlMapType, value: Map[WdlValue, WdlValue]) extends WdlValue { + val typesUsedInKey = value.map { case (k,v) => k.wdlType }.toSet + + if (typesUsedInKey.size == 1 && typesUsedInKey.head != wdlType.keyType) + throw new UnsupportedOperationException(s"Could not construct a $wdlType as this value: $value") + + if (typesUsedInKey.size > 1) + throw new UnsupportedOperationException(s"Cannot construct $wdlType with mixed types: $value") + + val typesUsedInValue = value.map { case (k,v) => v.wdlType }.toSet + + if (typesUsedInValue.size == 1 && typesUsedInValue.head != wdlType.valueType) + throw new UnsupportedOperationException(s"Could not construct a $wdlType as this value: $value") + + if (typesUsedInValue.size > 1) + throw new UnsupportedOperationException(s"Cannot construct $wdlType with mixed types: $value") + + override def toWdlString: String = + "{" + value.map {case (k,v) => s"${k.toWdlString}: ${v.toWdlString}"}.mkString(", ") + "}" + + def tsvSerialize: Try[String] = { + (wdlType.keyType, wdlType.valueType) match { + case (k: WdlPrimitiveType, v: WdlPrimitiveType) => + Success(value.map({case (k, v) => s"${k.valueString}\t${v.valueString}"}).mkString("\n")) + case _ => + Failure(new UnsupportedOperationException("Can only TSV serialize a Map[Primitive, Primitive]")) + } + } +} \ No newline at end of file diff --git a/src/main/scala/cromwell/binding/values/WdlValueJsonFormatter.scala b/src/main/scala/cromwell/binding/values/WdlValueJsonFormatter.scala index ef96299ce30..b4c4e7560be 100644 --- a/src/main/scala/cromwell/binding/values/WdlValueJsonFormatter.scala +++ b/src/main/scala/cromwell/binding/values/WdlValueJsonFormatter.scala @@ -5,13 +5,14 @@ import spray.json._ object WdlValueJsonFormatter extends DefaultJsonProtocol { implicit object WdlValueJsonFormat extends RootJsonFormat[WdlValue] { def write(value: WdlValue) = value match { - case s:WdlString => JsString(s.value) - case i:WdlInteger => JsNumber(i.value) - case f:WdlFloat => JsNumber(f.value) - case b:WdlBoolean => JsBoolean(b.value) - case f:WdlFile => JsString(f.value) - case o:WdlObject => JsObject() - case a:WdlArray => new JsArray(a.value.map(write).toVector) + case s: WdlString => JsString(s.value) + case i: WdlInteger => JsNumber(i.value) + case f: WdlFloat => JsNumber(f.value) + case b: WdlBoolean => JsBoolean(b.value) + case f: WdlFile => JsString(f.value) + case o: WdlObject => JsObject() + case a: WdlArray => new JsArray(a.value.map(write).toVector) + case m: WdlMap => new JsObject(m.value map {case(k,v) => k.valueString -> write(v)}) } def read(value: JsValue) = ??? } diff --git a/src/main/scala/cromwell/engine/CallActor.scala b/src/main/scala/cromwell/engine/CallActor.scala index 6e5b852bd4e..5abb8a87bb9 100644 --- a/src/main/scala/cromwell/engine/CallActor.scala +++ b/src/main/scala/cromwell/engine/CallActor.scala @@ -1,81 +1,125 @@ package cromwell.engine -import akka.actor.{Actor, Props} -import akka.event.{Logging, LoggingReceive} +import akka.actor.FSM.NullFunction +import akka.actor.{LoggingFSM, Props} import cromwell.binding._ import cromwell.binding.values.WdlValue -import cromwell.engine -import cromwell.engine.backend.Backend +import cromwell.engine.CallActor.CallActorState +import cromwell.engine.backend.{TaskAbortedException, Backend} import cromwell.engine.workflow.WorkflowActor import cromwell.engine.workflow.WorkflowActor.CallFailed import scala.language.postfixOps -import scala.util.{Failure, Success} - +import scala.util.{Try, Failure, Success} object CallActor { + sealed trait CallActorMessage - case class Start(inputs: CallInputs) extends CallActorMessage - case class ExecutionFinished(outputs: CallOutputs) extends CallActorMessage - case class ExecutionFailed(regret: Throwable) extends CallActorMessage + case object Start extends CallActorMessage + final case class RegisterCallAbortFunction(abortFunction: AbortFunction) extends CallActorMessage + case object AbortCall extends CallActorMessage + final case class ExecutionFinished(call: Call, outputs: Try[CallOutputs]) extends CallActorMessage + + sealed trait CallActorState + case object CallNotStarted extends CallActorState + case object CallRunningAbortUnavailable extends CallActorState + case object CallRunningAbortAvailable extends CallActorState + case object CallRunningAbortRequested extends CallActorState + case object CallAborting extends CallActorState + case object CallDone extends CallActorState - def props(call: Call, locallyQualifiedInputs: Map[String, WdlValue], backend: Backend, workflowDescriptor: WorkflowDescriptor): Props = + def props(call: Call, locallyQualifiedInputs: CallInputs, backend: Backend, workflowDescriptor: WorkflowDescriptor): Props = Props(new CallActor(call, locallyQualifiedInputs, backend, workflowDescriptor)) } /** Actor to manage the execution of a single call. */ -class CallActor(call: Call, locallyQualifiedInputs: Map[String, WdlValue], backend: Backend, workflowDescriptor: WorkflowDescriptor) extends Actor with CromwellActor { +class CallActor(call: Call, locallyQualifiedInputs: CallInputs, backend: Backend, workflowDescriptor: WorkflowDescriptor) + extends LoggingFSM[CallActorState, Option[AbortFunction]] with CromwellActor { + + import CallActor._ type CallOutputs = Map[String, WdlValue] - private val log = Logging(context.system, classOf[CallActor]) - val tag = s"CallActor [UUID(${workflowDescriptor.shortId}):${call.name}]" - - override def receive = LoggingReceive { - case CallActor.Start => handleStart() - case CallActor.ExecutionFinished(outputs) => context.parent ! WorkflowActor.CallCompleted(call, outputs) - case CallActor.ExecutionFailed(regret) => - log.error(regret, s"$tag: ${regret.getMessage}") - context.parent ! WorkflowActor.CallFailed(call, regret.getMessage) - case badMessage => - val diagnostic = s"$tag: unexpected message $badMessage." - log.error(diagnostic) - context.parent ! engine.workflow.WorkflowActor.CallFailed(call, diagnostic) + startWith(CallNotStarted, None) + + val callReference = CallReference(workflowDescriptor.name, workflowDescriptor.id, call.fullyQualifiedName) + val tag = s"CallActor [$callReference]" + + // Called on every state transition. + onTransition { + case fromState -> toState => + // Only log this at debug - these states are never seen or used outside of the CallActor itself. + log.debug(s"$tag transitioning from $fromState to $toState.") } - /** - * Performs the following steps: - *
    - *
  1. Instantiates the command line using these inputs.
  2. - *
  3. If the above completes successfully, messages the sender with `Started`, - * otherwise messages `Failed`.
  4. - *
  5. Executes the command with these inputs.
  6. - *
  7. Collects outputs in a `Try[Map[String, WdlValue]]`.
  8. - *
  9. If there are no `Failure`s among the outputs, messages the parent actor - * with `Completed`, otherwise messages `Failed`.
  10. - *
- */ - private def handleStart(): Unit = { - // Record the original sender here and not in the yield over the `Future`, as the - // value of sender() when that code executes may be different than what it is here. - val originalSender = sender() - val backendInputs = backend.adjustInputPaths(call, locallyQualifiedInputs) - - def failedInstantiation(e: Throwable): Unit = { - val message = s"Call '${call.fullyQualifiedName}' failed to launch command: " + e.getMessage - log.error(e, s"$tag: $message") - context.parent ! CallFailed(call, message) - } + when(CallNotStarted) { + case Event(Start, _) => + val backendInputs = backend.adjustInputPaths(call, locallyQualifiedInputs) + call.instantiateCommandLine(backendInputs, backend.setupCallEnvironment(call, workflowDescriptor).engineFunctions) match { + case Success(commandLine) => + sender() ! WorkflowActor.CallStarted(call) + context.actorOf(CallExecutionActor.props(callReference)) ! CallExecutionActor.Execute(workflowDescriptor.id, backend, commandLine, workflowDescriptor, call, backendInputs, inputName => locallyQualifiedInputs.get(inputName).get) + goto(CallRunningAbortUnavailable) + case Failure(e) => + val message = s"Call '${call.fullyQualifiedName}' failed to launch command: " + e.getMessage + log.error(e, s"$tag: $call failed: $message") + context.parent ! CallFailed(call, message) + goto(CallDone) + } + case Event(AbortCall, _) => handleFinished(call, Failure(new TaskAbortedException())) + } - def launchCall(commandLine: String): Unit = { - log.info(s"$tag: launching `$commandLine`") - originalSender ! WorkflowActor.CallStarted(call) - context.actorOf(CallExecutionActor.props(backend, commandLine, workflowDescriptor, call, backendInputs, inputName => locallyQualifiedInputs.get(inputName).get)) + when(CallRunningAbortUnavailable) { + case Event(RegisterCallAbortFunction(abortFunction), _) => goto(CallRunningAbortAvailable) using Option(abortFunction) + case Event(AbortCall, _) => goto(CallRunningAbortRequested) + } + + when(CallRunningAbortAvailable) { + case Event(AbortCall, abortFunction) => tryAbort(abortFunction) + } + + when(CallRunningAbortRequested) { + case Event(RegisterCallAbortFunction(abortFunction: AbortFunction), _) => tryAbort(Option(abortFunction)) + } + + // When in CallAborting, the only message being listened for is the CallComplete message (which is already + // handled by whenUnhandled.) + when(CallAborting) { NullFunction } + + when(CallDone) { + case Event(e, _) => + log.warning(s"$tag received unexpected event $e while in state $stateName") + stay() + } + + whenUnhandled { + case Event(ExecutionFinished(call: Call, outputs: Try[CallOutputs]), _) => handleFinished(call, outputs) + case Event(e, _) => + log.warning(s"$tag received unhandled event $e while in state $stateName") + stay() + } + + private def tryAbort(abortFunction: Option[AbortFunction]): CallActor.this.State = { + abortFunction match { + case Some(af) => + log.info("Abort function called.") + af.function() + goto(CallAborting) using abortFunction + case None => + log.warning("Call abort failed because the provided abort function was null.") + goto(CallRunningAbortRequested) using abortFunction } + } - call.instantiateCommandLine(backendInputs) match { - case Success(commandLine) => launchCall(commandLine) - case Failure(e) => failedInstantiation(e) + private def handleFinished(call: Call, outputTry: Try[CallOutputs]): CallActor.this.State = { + outputTry match { + case Success(outputs) => context.parent ! WorkflowActor.CallCompleted(call, outputs) + case Failure(e: TaskAbortedException) => + context.parent ! WorkflowActor.AbortComplete(call) + case Failure(e: Throwable) => + context.parent ! WorkflowActor.CallFailed(call, e.getMessage) } + + goto(CallDone) } } diff --git a/src/main/scala/cromwell/engine/CallExecutionActor.scala b/src/main/scala/cromwell/engine/CallExecutionActor.scala index cb83d78b37e..eed2e690221 100644 --- a/src/main/scala/cromwell/engine/CallExecutionActor.scala +++ b/src/main/scala/cromwell/engine/CallExecutionActor.scala @@ -4,39 +4,70 @@ import akka.actor.{Actor, Props} import akka.event.{Logging, LoggingReceive} import cromwell.binding.WdlExpression.ScopedLookupFunction import cromwell.binding.{Call, CallInputs, WorkflowDescriptor} -import cromwell.engine.backend.Backend +import cromwell.engine.backend.{TaskAbortedException, Backend} import scala.language.postfixOps -import scala.util.{Failure, Success} - +import scala.util.{Success, Failure} object CallExecutionActor { - def props(backend: Backend, command: String, workflowDescriptor: WorkflowDescriptor, call: Call, callInputs: CallInputs, lookup: ScopedLookupFunction): Props = - Props(new CallExecutionActor(backend, command, workflowDescriptor, call, callInputs, lookup)) + + sealed trait CallExecutionActorMessage + case class Execute(workflowId: WorkflowId, + backend: Backend, + command: String, + workflowDescriptor: WorkflowDescriptor, + call: Call, + callInputs: CallInputs, + lookup: ScopedLookupFunction) extends CallExecutionActorMessage + + def props(callReference: CallReference): Props = Props(new CallExecutionActor(callReference)) } /** Actor to manage the execution of a single call. */ -class CallExecutionActor(backend: Backend, command: String, workflowDescriptor: WorkflowDescriptor, call: Call, callInputs: CallInputs, lookup: ScopedLookupFunction) extends Actor with CromwellActor { +class CallExecutionActor(callReference: CallReference) extends Actor with CromwellActor { + import CallExecutionActor._ + private val log = Logging(context.system, classOf[CallExecutionActor]) - val tag = s"CallExecutionActor [UUID(${workflowDescriptor.shortId}):${call.name}]" - - log.info(s"$tag: starting.") - backend.executeCommand(command, workflowDescriptor, call, callInputs, lookup) match { - case Success(callOutputs) => - log.info(s"$tag: successful execution.") - context.parent ! CallActor.ExecutionFinished(callOutputs) - case Failure(e) => - log.error(s"$tag: failed execution.") - context.parent ! CallActor.ExecutionFailed(e) + + def tag = s"CallExecutionActor [$callReference]" + + private def execute(workflowId: WorkflowId, + backend: Backend, + command: String, + workflowDescriptor: WorkflowDescriptor, + call: Call, + callInputs: CallInputs, + lookup: ScopedLookupFunction) = { + + log.info(s"$tag: starting ${call.name} for workflow ${workflowDescriptor.shortId}") + log.info(s"$tag: `$command`") + + val executionResult = backend.executeCommand( + command, + workflowDescriptor, + call, + callInputs, + lookup, + AbortFunctionRegistration(registerAbortFunction(callReference))) + + executionResult match { + case Success(_) => log.info(s"$tag: successful execution.") + case Failure(e: TaskAbortedException) => log.info(s"$tag: aborted.") + case Failure(e) => log.error(s"$tag: failed execution - ${e.getMessage}") + } + + context.parent ! CallActor.ExecutionFinished(call, executionResult) } - /** - * The `CallExecutionActor` is not meant to respond to messages, it just starts up, does its work, - * and shuts down. - */ override def receive = LoggingReceive { + case Execute(workflowId, backend, command, workflowDescription, call, callInputs, lookup) => + execute(workflowId, backend, command, workflowDescription, call, callInputs, lookup) case badMessage => val diagnostic = s"$tag: unexpected message $badMessage." log.error(diagnostic) } + + private def registerAbortFunction(callReference: CallReference)(abortFunction: AbortFunction): Unit = { + context.parent ! CallActor.RegisterCallAbortFunction(abortFunction) + } } diff --git a/src/main/scala/cromwell/engine/CromwellActor.scala b/src/main/scala/cromwell/engine/CromwellActor.scala index 1268126e671..11d19aacc3f 100644 --- a/src/main/scala/cromwell/engine/CromwellActor.scala +++ b/src/main/scala/cromwell/engine/CromwellActor.scala @@ -1,6 +1,7 @@ package cromwell.engine import akka.util.Timeout + import scala.concurrent.duration._ import scala.language.postfixOps diff --git a/src/main/scala/cromwell/engine/EngineFunctions.scala b/src/main/scala/cromwell/engine/EngineFunctions.scala deleted file mode 100644 index fe1fe4fca80..00000000000 --- a/src/main/scala/cromwell/engine/EngineFunctions.scala +++ /dev/null @@ -1,33 +0,0 @@ -package cromwell.engine - -import cromwell.binding.WdlFunctions -import cromwell.binding.values._ - -import scala.util.{Failure, Try} - -trait EngineFunctions extends WdlFunctions { - protected def read_lines(params: Seq[Try[WdlValue]]): Try[WdlArray] - protected def read_int(params: Seq[Try[WdlValue]]): Try[WdlInteger] - protected def read_string(params: Seq[Try[WdlValue]]): Try[WdlString] - protected def stdout(params: Seq[Try[WdlValue]]): Try[WdlFile] - protected def stderr(params: Seq[Try[WdlValue]]): Try[WdlFile] - - /** - * Extract a single `WdlValue` from the specified `Seq`, returning `Failure` if the parameters - * represent something other than a single `WdlValue`. - */ - protected def extractSingleArgument(params: Seq[Try[WdlValue]]): Try[WdlValue] = { - if (params.length != 1) Failure(new UnsupportedOperationException("Expected one argument, got " + params.length)) - else params.head - } - - def getFunction(name: String): WdlFunction = { - name match { - case "read_lines" => read_lines - case "read_int" => read_int - case "read_string" => read_string - case "stdout" => stdout - case "stderr" => stderr - } - } -} diff --git a/src/main/scala/cromwell/engine/backend/Backend.scala b/src/main/scala/cromwell/engine/backend/Backend.scala index cf625e292c2..8db5816a4c4 100644 --- a/src/main/scala/cromwell/engine/backend/Backend.scala +++ b/src/main/scala/cromwell/engine/backend/Backend.scala @@ -1,11 +1,14 @@ package cromwell.engine.backend +import java.io.FileNotFoundException +import java.nio.file.{Files, Paths} + import com.typesafe.config.Config import cromwell.binding import cromwell.binding.WdlExpression.ScopedLookupFunction import cromwell.binding._ -import cromwell.binding.types.WdlFileType -import cromwell.binding.values.{WdlFile, WdlString, WdlValue} +import cromwell.binding.types.{WdlFileType, WdlMapType} +import cromwell.binding.values.{WdlFile, WdlMap, WdlString, WdlValue} import cromwell.engine._ import cromwell.engine.backend.Backend.RestartableWorkflow import cromwell.engine.backend.jes.JesBackend @@ -49,6 +52,15 @@ trait Backend { */ def initializeForWorkflow(workflow: WorkflowDescriptor): HostInputs + /** + * Given a Call and a WorkflowDescriptor, returns a *deterministic* TaskExecutionContext. This object + * should contain enough information to implement some or all of the WDL standard library functions. + * + * setupCallEnvironment() MUST also be idempotent. Any side effects it does (e.g. creating directories / buckets) + * should be able to handle being called more than once. + */ + def setupCallEnvironment(call: Call, workflowDescriptor: WorkflowDescriptor): TaskExecutionContext + /** * Execute the specified command line using the provided symbol store, evaluating the task outputs to produce * a mapping of local task output names to WDL values. @@ -57,7 +69,8 @@ trait Backend { workflowDescriptor: WorkflowDescriptor, call: Call, backendInputs: CallInputs, - scopedLookupFunction: ScopedLookupFunction): Try[Map[String, WdlValue]] + scopedLookupFunction: ScopedLookupFunction, + abortFunctionRegistration: AbortFunctionRegistration): Try[Map[String, WdlValue]] /** * Do whatever is appropriate for this backend implementation to support restarting the specified workflows. @@ -95,7 +108,8 @@ trait Backend { def outputAutoConversion(callFqn: String, taskOutput: TaskOutput, rawOutputValue: WdlValue): Try[WdlValue] = { rawOutputValue match { // Autoconvert String -> File. - case v: WdlString if taskOutput.wdlType == WdlFileType => Success(WdlFile(hostAbsoluteFilePath(v.value))) + case v: WdlString if taskOutput.wdlType == WdlFileType => assertTaskOutputPathExists(hostAbsoluteFilePath(v.value), taskOutput, callFqn) + case m: WdlMap if taskOutput.wdlType.isInstanceOf[WdlMapType] => taskOutput.wdlType.coerceRawValue(m) // Pass through matching types. case v if v.wdlType == taskOutput.wdlType => Success(v) // Fail other mismatched types. @@ -126,5 +140,14 @@ trait Backend { } } + private def assertTaskOutputPathExists(path: String, taskOutput: TaskOutput, callFqn: String): Try[WdlFile] = + if (Files.exists(Paths.get(path))) Success(WdlFile(path)) + else Failure(new FileNotFoundException( + s"""ERROR: Could not process output '${taskOutput.wdlType.toWdlString} ${taskOutput.name}' of $callFqn: + | + |Invalid path: $path + """.stripMargin + )) + def backendType: BackendType } diff --git a/src/main/scala/cromwell/engine/backend/TaskAbortedException.scala b/src/main/scala/cromwell/engine/backend/TaskAbortedException.scala new file mode 100644 index 00000000000..12bf79b4e5a --- /dev/null +++ b/src/main/scala/cromwell/engine/backend/TaskAbortedException.scala @@ -0,0 +1,5 @@ +package cromwell.engine.backend + +class TaskAbortedException extends Exception { + override def getMessage: String = "The task was aborted." +} diff --git a/src/main/scala/cromwell/engine/backend/TaskExecutionContext.scala b/src/main/scala/cromwell/engine/backend/TaskExecutionContext.scala new file mode 100644 index 00000000000..7a19da03dca --- /dev/null +++ b/src/main/scala/cromwell/engine/backend/TaskExecutionContext.scala @@ -0,0 +1,27 @@ +package cromwell.engine.backend + +import cromwell.binding.WdlStandardLibraryFunctions + +/** + * TaskExecutionContext represents the static information about a specific Call's invocation. + * + * For the LocalBackend, this would hold information like the Call's current working directory + * where it executes the command and a path to stdout/stderr files (which might not exist yet). + * + * An object with this trait is available to all WDL standard library functions. + * This makes it possible to implement WDL functions like read_lines and write_lines, + * which need have some execution context in order to work. + */ +trait TaskExecutionContext { + + /** + * Return the implementation of all WDL functions (e.g. read_lines(), stdout()) used + * by this backend. One situation in which this is called is to get the function implementations + * needed to instantiate the command line, which might contain a function call in it. + * + * See setupCallEnvironment() or TaskExecutionContext for more details + * + * For example: ./script ${write_lines(some_array)} + */ + def engineFunctions: WdlStandardLibraryFunctions +} diff --git a/src/main/scala/cromwell/engine/backend/jes/JesBackend.scala b/src/main/scala/cromwell/engine/backend/jes/JesBackend.scala index 0d705a87d30..72f5c0bde70 100644 --- a/src/main/scala/cromwell/engine/backend/jes/JesBackend.scala +++ b/src/main/scala/cromwell/engine/backend/jes/JesBackend.scala @@ -1,6 +1,7 @@ package cromwell.engine.backend.jes import java.math.BigInteger +import java.net.URL import java.nio.file.{Path, Paths} import com.google.api.services.genomics.model.Parameter @@ -10,11 +11,12 @@ import cromwell.binding.WdlExpression._ import cromwell.binding._ import cromwell.binding.types.WdlFileType import cromwell.binding.values._ -import cromwell.engine.WorkflowId -import cromwell.engine.backend.{StdoutStderr, Backend} +import cromwell.engine.{AbortFunction, AbortFunctionRegistration} +import cromwell.engine.backend.{TaskExecutionContext, TaskAbortedException, Backend, StdoutStderr} import cromwell.engine.backend.Backend.RestartableWorkflow import cromwell.engine.backend.jes.JesBackend._ import cromwell.engine.db.DataAccess +import cromwell.engine.WorkflowId import cromwell.parser.BackendType import cromwell.util.TryUtil import cromwell.util.google.GoogleCloudStoragePath @@ -27,8 +29,8 @@ object JesBackend { lazy val GoogleProject = JesConf.getString("project") lazy val GoogleApplicationName = JesConf.getString("applicationName") lazy val CromwellExecutionBucket = JesConf.getString("baseExecutionBucket") - - lazy val JesConnection = JesInterface(GoogleApplicationName) + lazy val EndpointUrl = new URL(JesConf.getString("endpointUrl")) + lazy val JesConnection = JesInterface(GoogleApplicationName, EndpointUrl) /* FIXME: At least for now the only files that can be used are stdout/stderr. However this leads to a problem @@ -110,13 +112,18 @@ class JesBackend extends Backend with LazyLogging { override def initializeForWorkflow(workflow: WorkflowDescriptor): HostInputs = workflow.actualInputs def taskOutputToJesOutput(taskOutput: TaskOutput, callGcsPath: String, scopedLookupFunction: ScopedLookupFunction, engineFunctions: JesEngineFunctions): Try[Option[JesOutput]] = { - taskOutput.wdlType match { - case WdlFileType => - taskOutput.expression.evaluate(scopedLookupFunction, engineFunctions, interpolateStrings = true) match { - case Success(v) => Success(Option(JesOutput(taskOutput.name, s"$callGcsPath/${taskOutput.name}", Paths.get(v.valueString)))) - case Failure(e) => Failure(new IllegalArgumentException(s"JES requires File outputs to be determined prior to running, but ${taskOutput.name} can not.")) - } - case _ => Success(None) + // If the output isn't a file then it's not a file to be retrieved by the JES run! (but NB: see anonymous task output below) + // Currently, no function calls can be run before the JES call completes, so we can't retrieve files with names based on function calls. + if (taskOutput.wdlType != WdlFileType || taskOutput.expression.containsFunctionCall) { + Success(None) + } else { + val evaluatedExpression = taskOutput.expression.evaluate(scopedLookupFunction, engineFunctions, interpolateStrings = true) + evaluatedExpression match { + case Success(v) => + val jesOutput = JesOutput(taskOutput.name, s"$callGcsPath/${taskOutput.name}", Paths.get(v.valueString)) + Success(Option(jesOutput)) + case Failure(e) => Failure(new IllegalArgumentException(s"JES requires File outputs to be determined prior to running, but ${taskOutput.name} can not.")) + } } } @@ -143,33 +150,43 @@ class JesBackend extends Backend with LazyLogging { ) } + override def setupCallEnvironment(call: Call, workflowDescriptor: WorkflowDescriptor): JesTaskExecutionContext = { + val callGcsPath = s"${workflowDescriptor.callDir(call)}" + JesTaskExecutionContext(GoogleCloudStoragePath(callGcsPath), JesConnection) + } + override def executeCommand(instantiatedCommandLine: String, workflowDescriptor: WorkflowDescriptor, call: Call, backendInputs: CallInputs, - scopedLookupFunction: ScopedLookupFunction): Try[Map[String, WdlValue]] = { - val callGcsPath = s"${workflowDescriptor.callDir(call)}" + scopedLookupFunction: ScopedLookupFunction, + abortFunctionRegistration: AbortFunctionRegistration): Try[Map[String, WdlValue]] = { - val engineFunctions = new JesEngineFunctions(GoogleCloudStoragePath(callGcsPath), JesConnection) + val callGcsPath = s"${workflowDescriptor.callDir(call)}" + logger.info(s"JES log directory in GCS: $callGcsPath") + val gcsExecPath = GoogleCloudStoragePath(callGcsPath + "/exec.sh") + val cmdInput = JesInput("exec", gcsExecPath.toString, Paths.get("exec.sh")) + val environment = setupCallEnvironment(call, workflowDescriptor) - // FIXME: Not particularly robust at the moment. val jesInputs: Seq[JesParameter] = backendInputs.collect({ case (k, v) if v.isInstanceOf[WdlFile] => JesInput(k, scopedLookupFunction(k).valueString, Paths.get(v.valueString)) - }).toSeq + }).toSeq :+ cmdInput // Call preevaluateExpressionForFilenames for each of the task output expressions, and flatten the lists into a single Try[Seq[WdlFile]] val filesWithinExpressions = Try( call.task.outputs.map { - taskOutput => taskOutput.expression.preevaluateExpressionForFilenames(scopedLookupFunction, engineFunctions) + taskOutput => taskOutput.expression.preevaluateExpressionForFilenames(scopedLookupFunction, environment.engineFunctions) }.flatMap({_.get}) ) + // Find the named and anonymous outputs to retrieve from the JES docker image. Doesn't necessarily include ALL + // eventual outputs (e.g. String s = stdout() won't need anything extracted from the JES container). val jesOutputs: Try[Seq[JesParameter]] = filesWithinExpressions match { case Failure(error) => Failure(error) case Success(fileSeq) => - val anonOutputs: Seq[JesParameter] = fileSeq map {x => anonymousTaskOutput(x.value, engineFunctions)} + val anonOutputs: Seq[JesParameter] = fileSeq map {x => anonymousTaskOutput(x.value, environment.engineFunctions)} // FIXME: If localizeTaskOutputs gives a Failure, need to Fail entire function - don't use .get - val namedOutputs: Seq[JesParameter] = taskOutputsToJesOutputs(call.task.outputs, callGcsPath, scopedLookupFunction, engineFunctions).get + val namedOutputs: Seq[JesParameter] = taskOutputsToJesOutputs(call.task.outputs, callGcsPath, scopedLookupFunction, environment.engineFunctions).get Success(anonOutputs ++ namedOutputs) } @@ -179,36 +196,47 @@ class JesBackend extends Backend with LazyLogging { val jesParameters = standardParameters(callGcsPath) ++ jesInputs ++ unsafeJesOutputs // Not possible to currently get stdout/stderr so redirect everything and hope the WDL isn't doing that too - val redirectedCommand = s"$instantiatedCommandLine > $LocalStdoutValue 2> $LocalStderrValue" - - val status = Pipeline(redirectedCommand, workflowDescriptor, call, jesParameters, GoogleProject, JesConnection).run.waitUntilComplete() - - def taskOutputToRawValue(taskOutput: TaskOutput): Try[WdlValue] = { - val jesOutputFile = unsafeJesOutputs find {_.name == taskOutput.name} map {j => WdlFile(j.gcs)} - jesOutputFile.map(Success(_)).getOrElse(taskOutput.expression.evaluate(scopedLookupFunction, engineFunctions, interpolateStrings = true)) - } - - val outputMappings = call.task.outputs.map { taskOutput => - val rawValue = taskOutputToRawValue(taskOutput) - logger.debug(s"JesBackend setting ${taskOutput.name} to $rawValue") - taskOutput.name -> rawValue - }.toMap + JesConnection.storage.uploadObject(gcsExecPath, instantiatedCommandLine) + + val run = Pipeline(s"/bin/bash exec.sh > $LocalStdoutValue 2> $LocalStderrValue", workflowDescriptor, call, jesParameters, GoogleProject, JesConnection).run + // Wait until the job starts (or completes/fails) before registering the abort to avoid awkward cancel-during-initialization behavior. + run.waitUntilRunningOrComplete() + abortFunctionRegistration.registrationFunction apply AbortFunction({() => run.abort()}) + try { + val status = run.waitUntilComplete(None) + + def taskOutputToRawValue(taskOutput: TaskOutput): Try[WdlValue] = { + val jesOutputFile = unsafeJesOutputs find { _.name == taskOutput.name } map { j => WdlFile(j.gcs) } + jesOutputFile.map(Success(_)).getOrElse(taskOutput.expression.evaluate(scopedLookupFunction, environment.engineFunctions, interpolateStrings = true)) + } - val warnAboutStderrLength: BigInteger = - if (!call.failOnStderr) BigInteger.valueOf(0) - else JesConnection.storage.objectSize(GoogleCloudStoragePath(stderrJesOutput(callGcsPath).gcs)) + def processOutput(taskOutput: TaskOutput, processingFunction: TaskOutput => Try[WdlValue]) = { + val rawValue = processingFunction(taskOutput) + logger.debug(s"JesBackend setting ${taskOutput.name} to $rawValue") + taskOutput.name -> rawValue + } - if (warnAboutStderrLength.intValue > 0) { - Failure(new Throwable(s"Workflow ${workflowDescriptor.id}: stderr has length $warnAboutStderrLength for command: $instantiatedCommandLine")) - } else { - status match { - // - case Run.Success(created, started, finished) => - unwrapOutputValues(outputMappings, workflowDescriptor) - case Run.Failed(created, started, finished, errorCode, errorMessage) => - Failure(new Throwable(s"Workflow ${workflowDescriptor.id}: errorCode $errorCode for command: $instantiatedCommandLine. Message: $errorMessage")) + val outputMappings = call.task.outputs.map {taskOutput => processOutput(taskOutput, taskOutputToRawValue)}.toMap + + lazy val stderrLength: BigInteger = JesConnection.storage.objectSize(GoogleCloudStoragePath(stderrJesOutput(callGcsPath).gcs)) + + if (call.failOnStderr && stderrLength.intValue > 0) { + Failure(new Throwable(s"Workflow ${workflowDescriptor.id}: stderr has length $stderrLength for command: $instantiatedCommandLine")) + } else status match { + case Run.Success => + unwrapOutputValues(outputMappings, workflowDescriptor) + case Run.Failed(errorCode, errorMessage) => + val throwable = if (errorMessage contains "Operation canceled at") { + new TaskAbortedException() + } else { + new Throwable(s"Workflow ${workflowDescriptor.id}: errorCode $errorCode for command: $instantiatedCommandLine. Message: $errorMessage") + } + Failure(throwable) } } + catch { + case e: Exception => Failure(e) + } } def unwrapOutputValues(outputMappings: Map[String, Try[WdlValue]], workflowDescriptor: WorkflowDescriptor): Try[Map[String, WdlValue]] = { diff --git a/src/main/scala/cromwell/engine/backend/jes/JesEngineFunctions.scala b/src/main/scala/cromwell/engine/backend/jes/JesEngineFunctions.scala index e7dc0f2fa8b..26b93a5218f 100644 --- a/src/main/scala/cromwell/engine/backend/jes/JesEngineFunctions.scala +++ b/src/main/scala/cromwell/engine/backend/jes/JesEngineFunctions.scala @@ -2,24 +2,24 @@ package cromwell.engine.backend.jes import java.security.MessageDigest -import cromwell.binding.types.{WdlStringType, WdlArrayType} +import cromwell.binding.WdlStandardLibraryFunctions +import cromwell.binding.types.{WdlArrayType, WdlStringType} import cromwell.binding.values._ -import cromwell.engine.EngineFunctions import cromwell.util.google.GoogleCloudStoragePath - import org.apache.commons.codec.binary.Base64 -import scala.util.{Failure, Success, Try} +import scala.util.{Success, Try} /** * Implementation of engine functions for the JES backend. */ -case class JesEngineFunctions(callDir: GoogleCloudStoragePath, jesConnection: JesInterface) extends EngineFunctions { +//case class JesEngineFunctions(executionContext.callDir: GoogleCloudStoragePath, jesConnection: JesInterface) extends WdlStandardLibraryFunctions { +case class JesEngineFunctions(executionContext: JesTaskExecutionContext) extends WdlStandardLibraryFunctions { private def readFromPath(value: String): String = { val tryParse = GoogleCloudStoragePath.parse(value) val gcsPathToUse: GoogleCloudStoragePath = if (tryParse.isSuccess) { tryParse.get } else { GoogleCloudStoragePath(gcsPathFromAnyString(value)) } - jesConnection.storage.slurpFile(gcsPathToUse) + executionContext.jesConnection.storage.slurpFile(gcsPathToUse) } /** @@ -38,13 +38,29 @@ case class JesEngineFunctions(callDir: GoogleCloudStoragePath, jesConnection: Je } } - protected def read_lines(params: Seq[Try[WdlValue]]): Try[WdlArray] = { + override protected def stdout(params: Seq[Try[WdlValue]]): Try[WdlFile] = { + val newPath = GoogleCloudStoragePath(executionContext.callDir.bucket, executionContext.callDir.objectName + "/" + JesBackend.LocalStdoutValue) + Success(WdlFile(newPath.toString)) + } + + override protected def stderr(params: Seq[Try[WdlValue]]): Try[WdlFile] = { + val newPath = GoogleCloudStoragePath(executionContext.callDir.bucket, executionContext.callDir.objectName + "/" + JesBackend.LocalStderrValue) + Success(WdlFile(newPath.toString)) + } + + override protected def read_lines(params: Seq[Try[WdlValue]]): Try[WdlArray] = { for { singleArgument <- extractSingleArgument(params) lines = fileContentsToString(singleArgument).split("\n").map{WdlString} } yield WdlArray(WdlArrayType(WdlStringType), lines) } + /** + * Try to read an integer from the file referenced by the specified `WdlValue`. + */ + override protected def read_int(params: Seq[Try[WdlValue]]): Try[WdlInteger] = + read_string(params) map { s => WdlInteger(s.value.trim.toInt) } + /** * Try to read a string from the file referenced by the specified `WdlValue`. */ @@ -55,24 +71,8 @@ case class JesEngineFunctions(callDir: GoogleCloudStoragePath, jesConnection: Je } yield WdlString(string) } - /** - * Try to read an integer from the file referenced by the specified `WdlValue`. - */ - override protected def read_int(params: Seq[Try[WdlValue]]): Try[WdlInteger] = - read_string(params).map { s => WdlInteger(s.value.trim.toInt) } - - override protected def stdout(params: Seq[Try[WdlValue]]): Try[WdlFile] = { - val newPath = GoogleCloudStoragePath(callDir.bucket, callDir.objectName + "/" + JesBackend.LocalStdoutValue) - Success(WdlFile(newPath.toString)) - } - - override protected def stderr(params: Seq[Try[WdlValue]]): Try[WdlFile] = { - val newPath = GoogleCloudStoragePath(callDir.bucket, callDir.objectName + "/" + JesBackend.LocalStderrValue) - Success(WdlFile(newPath.toString)) - } - def gcsPathFromAnyString(value: String) = { - callDir + md5(value) + executionContext.callDir + md5(value) } def md5(value: String): String = { diff --git a/src/main/scala/cromwell/engine/backend/jes/JesInterface.scala b/src/main/scala/cromwell/engine/backend/jes/JesInterface.scala index bd5f95a636a..9388ae80f95 100644 --- a/src/main/scala/cromwell/engine/backend/jes/JesInterface.scala +++ b/src/main/scala/cromwell/engine/backend/jes/JesInterface.scala @@ -12,11 +12,11 @@ import cromwell.util.google.{GoogleCloudStorage, GoogleCredentialFactory} object JesInterface { - def apply(appName: String): JesInterface = { + def apply(appName: String, endpointUrl: URL): JesInterface = { val jsonFactory = JacksonFactory.getDefaultInstance val httpTransport = GoogleNetHttpTransport.newTrustedTransport val credential = GoogleCredentialFactory.from(jsonFactory, httpTransport) - val genomics = GoogleGenomics.from(appName, credential, jsonFactory, httpTransport) + val genomics = GoogleGenomics.from(appName, endpointUrl, credential, jsonFactory, httpTransport) val storage = GoogleCloudStorage(appName, credential, jsonFactory, httpTransport) JesInterface(credential, genomics, storage) @@ -24,10 +24,8 @@ object JesInterface { // Wrapper object around Google's Genomics class providing a convenience 'from' "method" object GoogleGenomics { - def GenomicsUrl = new URL("https://staging-genomics.sandbox.googleapis.com") - - def from(applicationName: String, credential: Credential, jsonFactory: JsonFactory, httpTransport: HttpTransport): Genomics = { - new Genomics.Builder(httpTransport, jsonFactory, credential).setApplicationName(applicationName).setRootUrl(GenomicsUrl.toString).build + def from(applicationName: String, endpointUrl: URL, credential: Credential, jsonFactory: JsonFactory, httpTransport: HttpTransport): Genomics = { + new Genomics.Builder(httpTransport, jsonFactory, credential).setApplicationName(applicationName).setRootUrl(endpointUrl.toString).build } } } diff --git a/src/main/scala/cromwell/engine/backend/jes/JesRuntimeInfo.scala b/src/main/scala/cromwell/engine/backend/jes/JesRuntimeInfo.scala index 03efff3925a..2fd9cf694d3 100644 --- a/src/main/scala/cromwell/engine/backend/jes/JesRuntimeInfo.scala +++ b/src/main/scala/cromwell/engine/backend/jes/JesRuntimeInfo.scala @@ -14,7 +14,7 @@ object JesRuntimeInfo { def buildDockerExecutor(commandLine: String, dockerImage: String): DockerExecutor = { val docker = new DockerExecutor() - docker.setImage(dockerImage).setCmd(s"/bin/bash -c '$commandLine'") + docker.setImage(dockerImage).setCmd(commandLine) } def buildResources(call: Call): Resources = { diff --git a/src/main/scala/cromwell/engine/backend/jes/JesTaskExecutionContext.scala b/src/main/scala/cromwell/engine/backend/jes/JesTaskExecutionContext.scala new file mode 100644 index 00000000000..3697fb29b5d --- /dev/null +++ b/src/main/scala/cromwell/engine/backend/jes/JesTaskExecutionContext.scala @@ -0,0 +1,8 @@ +package cromwell.engine.backend.jes + +import cromwell.engine.backend.TaskExecutionContext +import cromwell.util.google.GoogleCloudStoragePath + +case class JesTaskExecutionContext(callDir: GoogleCloudStoragePath, jesConnection: JesInterface) extends TaskExecutionContext { + override def engineFunctions: JesEngineFunctions = new JesEngineFunctions(this) +} diff --git a/src/main/scala/cromwell/engine/backend/jes/OperationMetadata.scala b/src/main/scala/cromwell/engine/backend/jes/OperationMetadata.scala deleted file mode 100644 index b35bc00e3b8..00000000000 --- a/src/main/scala/cromwell/engine/backend/jes/OperationMetadata.scala +++ /dev/null @@ -1,24 +0,0 @@ -package cromwell.engine.backend.jes - -import java.text.SimpleDateFormat -import java.util.Date - -import com.google.api.services.genomics.model.Operation -import scala.collection.JavaConverters._ - -object OperationMetadata { - def apply(operation: Operation): OperationMetadata = { - val metadata = operation.getMetadata.asScala - new OperationMetadata(metadata("createTime").asInstanceOf[String].toDate, - metadata.get("startTime").map(_.asInstanceOf[String].toDate), - metadata.get("endTime").map(_.asInstanceOf[String].toDate)) - } - - val Iso8601DateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX") - - implicit class EnhancedString(val string: String) extends AnyVal { - def toDate: Date = Iso8601DateFormat.parse(string.asInstanceOf[String]) - } -} - -case class OperationMetadata(created: Date, started: Option[Date], finished: Option[Date]) diff --git a/src/main/scala/cromwell/engine/backend/jes/Pipeline.scala b/src/main/scala/cromwell/engine/backend/jes/Pipeline.scala index dd08b4fb829..f75e40b6afe 100644 --- a/src/main/scala/cromwell/engine/backend/jes/Pipeline.scala +++ b/src/main/scala/cromwell/engine/backend/jes/Pipeline.scala @@ -1,11 +1,12 @@ package cromwell.engine.backend.jes +import com.google.api.services.genomics.Genomics +import com.google.api.services.genomics.model.CreatePipelineRequest import com.typesafe.scalalogging.LazyLogging import cromwell.binding.{Call, WorkflowDescriptor} +import cromwell.engine.backend.jes.JesBackend._ + import scala.collection.JavaConverters._ -import com.google.api.services.genomics.Genomics -import com.google.api.services.genomics.model.CreatePipelineRequest -import JesBackend._ object Pipeline extends LazyLogging { def apply(command: String, workflow: WorkflowDescriptor, call: Call, jesParameters: Seq[JesParameter], projectId: String, jesConnection: JesInterface): Pipeline = { @@ -23,9 +24,9 @@ object Pipeline extends LazyLogging { cpr.setParameters(jesParameters.map(_.toGoogleParameter).toVector.asJava) - logger.debug(s"$tag Pipeline parameters are ${cpr.getParameters}") + logger.info(s"$tag Pipeline parameters are ${cpr.getParameters}") val pipelineId = jesConnection.genomics.pipelines().create(cpr).execute().getPipelineId - logger.debug(s"$tag Pipeline ID is $pipelineId") + logger.info(s"$tag Pipeline ID is $pipelineId") new Pipeline(command, pipelineId, projectId, gcsPath, workflow, call, jesParameters, jesConnection.genomics) } } diff --git a/src/main/scala/cromwell/engine/backend/jes/Run.scala b/src/main/scala/cromwell/engine/backend/jes/Run.scala index b319d08d41d..567b48cb943 100644 --- a/src/main/scala/cromwell/engine/backend/jes/Run.scala +++ b/src/main/scala/cromwell/engine/backend/jes/Run.scala @@ -1,16 +1,14 @@ package cromwell.engine.backend.jes -import java.util.Date - -import com.google.api.services.genomics.model.{Logging, Status, ServiceAccount, RunPipelineRequest} +import com.google.api.services.genomics.model.{CancelOperationRequest, Logging, RunPipelineRequest, ServiceAccount, _} import cromwell.engine.backend.jes.JesBackend.JesParameter -import cromwell.engine.backend.jes.Run.{Running, Success, Failed} +import cromwell.engine.backend.jes.Run.{Failed, Running, Success, _} import cromwell.util.google.GoogleScopes import org.slf4j.LoggerFactory + import scala.annotation.tailrec -import com.typesafe.scalalogging.{StrictLogging, LazyLogging} import scala.collection.JavaConverters._ -import Run._ +import scala.language.postfixOps object Run { val JesServiceAccount = new ServiceAccount().setEmail("default").setScopes(GoogleScopes.Scopes.asJava) @@ -30,50 +28,77 @@ object Run { rpr.setLogging(logging) val id = pipeline.genomicsService.pipelines().run(rpr).execute().getName - Log.info(s"$tag ID is $id") - new Run(id, pipeline) + Log.info(s"$tag JES ID is $id") + new Run(id, pipeline, tag) } implicit class RunJesParameters(val params: Seq[JesParameter]) extends AnyVal { def toRunMap = params.map(p => p.name -> p.gcs).toMap.asJava } + implicit class RunOperationExtension(val operation: Operation) extends AnyVal { + def hasStarted = operation.getMetadata.asScala.get("startTime") isDefined + } + sealed trait RunStatus trait TerminalRunStatus extends RunStatus - final case class Initializing(created: Date) extends RunStatus - final case class Running(created: Date, started: Date) extends RunStatus - final case class Success(created: Date, started: Date, finished: Date) extends TerminalRunStatus - final case class Failed(created: Date, started: Date, finished: Date, errorCode: Int, errorMessage: String) extends TerminalRunStatus + case object Initializing extends RunStatus + case object Running extends RunStatus + case object Success extends TerminalRunStatus + final case class Failed(errorCode: Int, errorMessage: String) extends TerminalRunStatus { + // Don't want to include errorMessage or code in the snappy status toString: + override def toString = "Failed" + } } -case class Run(name: String, pipeline: Pipeline) { +case class Run(name: String, pipeline: Pipeline, tag: String) { + def status(): RunStatus = { val op = pipeline.genomicsService.operations().get(name).execute - val metadata = OperationMetadata(op) if (op.getDone) { - val error = Option(op.getError) - error match { - case Some(x) => Failed( - metadata.created, - metadata.started.get, - metadata.finished.get, - x.getCode, - x.getMessage) - case None => Success(metadata.created, metadata.started.get, metadata.finished.get) - } - } else metadata.started map {s => Running(metadata.created, s)} getOrElse Initializing(metadata.created) + // If there's an error, generate a Failed status. Otherwise, we were successful! + Option(op.getError) map { x => Failed(x.getCode, x.getMessage) } getOrElse Success + } else if (op.hasStarted) { + Running + } else { + Initializing + } } @tailrec - final def waitUntilComplete(): TerminalRunStatus = { + final def waitUntilComplete(previousStatus: Option[RunStatus]): TerminalRunStatus = { val currentStatus = status() - println(s"Current status is $currentStatus") + + if (!(previousStatus contains currentStatus)) { + // If this is the first time checking the status, we log the transition as '-' to 'currentStatus'. Otherwise + // just use the state names. + val prevStateName = previousStatus map { _.toString } getOrElse "-" + Log.info(s"$tag: Status change from $prevStateName to $currentStatus") + } + currentStatus match { case x: TerminalRunStatus => x case _ => Thread.sleep(5000) - waitUntilComplete() + waitUntilComplete(Option(currentStatus)) } } -} \ No newline at end of file + + @tailrec + final def waitUntilRunningOrComplete(): Unit = { + val currentStatus = status() + currentStatus match { + case Initializing => // Done + case x: TerminalRunStatus => // Done + case _ => + Thread.sleep(5000) + waitUntilRunningOrComplete() + } + } + + def abort(): Unit = { + val cancellationRequest: CancelOperationRequest = new CancelOperationRequest() + pipeline.genomicsService.operations().cancel(name, cancellationRequest).execute + } +} diff --git a/src/main/scala/cromwell/engine/backend/local/LocalBackend.scala b/src/main/scala/cromwell/engine/backend/local/LocalBackend.scala index 6226ec4da24..293ee0c80a8 100644 --- a/src/main/scala/cromwell/engine/backend/local/LocalBackend.scala +++ b/src/main/scala/cromwell/engine/backend/local/LocalBackend.scala @@ -2,16 +2,16 @@ package cromwell.engine.backend.local import java.io.{File, Writer} import java.nio.file.{Files, Path, Paths} -import java.util.UUID import com.typesafe.scalalogging.LazyLogging import cromwell.binding.WdlExpression.ScopedLookupFunction import cromwell.binding._ import cromwell.binding.values.{WdlArray, WdlFile, WdlValue} -import cromwell.engine.backend.{StdoutStderr, Backend} +import cromwell.engine.backend.TaskAbortedException import cromwell.engine.backend.Backend.{RestartableWorkflow, StdoutStderrException} +import cromwell.engine.backend.{Backend, StdoutStderr} import cromwell.engine.db.{CallStatus, DataAccess} -import cromwell.engine.{ExecutionStatus, WorkflowId} +import cromwell.engine._ import cromwell.parser.BackendType import cromwell.util.FileUtil import cromwell.util.FileUtil._ @@ -60,13 +60,13 @@ object LocalBackend { def hostExecutionPath(workflow: WorkflowDescriptor): Path = hostExecutionPath(workflow.name, workflow.id) - def hostExecutionPath(workflowName: String, workflowUuid: UUID): Path = - Paths.get(CromwellExecutions, workflowName, workflowUuid.toString) + def hostExecutionPath(workflowName: String, workflowUuid: WorkflowId): Path = + Paths.get(CromwellExecutions, workflowName, workflowUuid.id.toString) def hostCallPath(workflow: WorkflowDescriptor, callName: String): Path = Paths.get(hostExecutionPath(workflow).toFile.getAbsolutePath, s"call-$callName") - def hostCallPath(workflowName: String, workflowUuid: UUID, callName: String): Path = + def hostCallPath(workflowName: String, workflowUuid: WorkflowId, callName: String): Path = Paths.get(hostExecutionPath(workflowName, workflowUuid).toFile.getAbsolutePath, s"call-$callName") } @@ -81,11 +81,21 @@ class LocalBackend extends Backend with LazyLogging { override def stdoutStderr(workflowId: WorkflowId, workflowName: String, callName: String): StdoutStderr = { val dir = hostCallPath(workflowName, workflowId, callName) StdoutStderr( - stdout = findTempFile(dir, prefix = "stdout"), - stderr = findTempFile(dir, prefix = "stderr") + stdout = WdlFile(dir.resolve("stdout").toAbsolutePath.toString), + stderr = WdlFile(dir.resolve("stderr").toAbsolutePath.toString) ) } + /* This should be deterministic. calling this twice with the same parameters should always yield the same result */ + def setupCallEnvironment(call: Call, workflowDescriptor: WorkflowDescriptor): LocalTaskExecutionContext = { + val workflowRoot = hostExecutionPath(workflowDescriptor) + val hostCallDirectory = hostCallPath(workflowDescriptor, call.name) + val stdout = hostCallDirectory.resolve("stdout") + val stderr = hostCallDirectory.resolve("stderr") + hostCallDirectory.toFile.mkdirs + LocalTaskExecutionContext(workflowRoot, stdout, stderr, hostCallDirectory) + } + /** * Executes the specified command line, using the supplied lookup function for expression evaluation. * Returns a `Map[String, Try[WdlValue]]` of output names to values. @@ -94,20 +104,18 @@ class LocalBackend extends Backend with LazyLogging { workflowDescriptor: WorkflowDescriptor, call: Call, backendInputs: CallInputs, - scopedLookupFunction: ScopedLookupFunction): Try[Map[String, WdlValue]] = { - - val workflowRootAbsolutePathOnHost = hostExecutionPath(workflowDescriptor).toFile.getAbsolutePath + scopedLookupFunction: ScopedLookupFunction, + callAbortRegisteringFunction: AbortFunctionRegistration): Try[Map[String, WdlValue]] = { - val hostCallDirectory = hostCallPath(workflowDescriptor, call.name).toFile - hostCallDirectory.mkdirs() + val environment = setupCallEnvironment(call, workflowDescriptor) - val (stdoutFile, stdoutWriter) = FileUtil.tempFileAndWriter("stdout", hostCallDirectory) - val (stderrFile, stderrWriter) = FileUtil.tempFileAndWriter("stderr", hostCallDirectory) - val (commandFile, commandWriter) = FileUtil.tempFileAndWriter("command", hostCallDirectory) + val (stdoutFile, stdoutWriter) = environment.stdout.fileAndWriter + val (stderrFile, stderrWriter) = environment.stderr.fileAndWriter + val (commandFile, commandWriter) = FileUtil.tempFileAndWriter("command", environment.cwd.toFile) val dockerContainerExecutionDir = s"/root/${workflowDescriptor.id.toString}" - val parentPath = if (call.docker.isDefined) Paths.get(dockerContainerExecutionDir).toString else workflowRootAbsolutePathOnHost + val parentPath = if (call.docker.isDefined) Paths.get(dockerContainerExecutionDir).toString else environment.workflowRoot.toAbsolutePath.toString val callDirectory = Paths.get(parentPath, s"call-${call.name}") commandWriter.writeWithNewline(s"cd $callDirectory") @@ -117,27 +125,28 @@ class LocalBackend extends Backend with LazyLogging { def buildDockerRunCommand(image: String): String = // -v maps the host workflow executions directory to /root/ on the container. // -i makes the run interactive, required for the cat and <&0 shenanigans that follow. - s"docker run -v $workflowRootAbsolutePathOnHost:$dockerContainerExecutionDir -i $image" + s"docker run -v ${environment.workflowRoot.toAbsolutePath}:$dockerContainerExecutionDir -i $image" // Build the docker run command if docker is defined in the RuntimeAttributes, otherwise just the empty string. - val dockerRun = call.docker.map { buildDockerRunCommand }.getOrElse("") + val dockerRun = call.docker.map(buildDockerRunCommand).getOrElse("") // The aforementioned shenanigans generate standard output and then a bash invocation that takes // commands from standard input. val argv = Seq("/bin/bash", "-c", s"cat $commandFile | $dockerRun /bin/bash <&0") logger.debug("Executing call with argv: " + argv) - // The ! to the ProcessLogger captures standard output and error. - val rc: Int = argv ! ProcessLogger(stdoutWriter writeWithNewline, stderrWriter writeWithNewline) - Vector(stdoutWriter, stderrWriter).foreach { _.flushAndClose() } + val process = argv.run(ProcessLogger(stdoutWriter writeWithNewline, stderrWriter writeWithNewline)) + + // TODO: As currently implemented, this process.destroy() will kill the bash process but *not* its descendants. See ticket DSDEEPB-848. + callAbortRegisteringFunction.registrationFunction(AbortFunction(() => process.destroy())) + val rc: Int = process.exitValue() + Vector(stdoutWriter, stderrWriter) foreach { _.flushAndClose() } /** * Return a host absolute file path. */ def hostAbsoluteFilePath(pathString: String): String = - if (new File(pathString).isAbsolute) pathString else Paths.get(hostCallDirectory.toString, pathString).toString - - val localEngineFunctions = new LocalEngineFunctions(TaskExecutionContext(stdoutFile, stderrFile, Paths.get(hostCallDirectory.getAbsolutePath))) + if (new File(pathString).isAbsolute) pathString else Paths.get(environment.cwd.toAbsolutePath.toString, pathString).toString val stderrFileLength = new File(stderrFile.toString).length @@ -145,7 +154,10 @@ class LocalBackend extends Backend with LazyLogging { Failure(new Throwable(s"Workflow ${workflowDescriptor.id}: stderr has length $stderrFileLength for command: $instantiatedCommandLine")) } else { if (rc == 0) { - evaluateCallOutputs(workflowDescriptor, call, hostAbsoluteFilePath, localEngineFunctions, scopedLookupFunction, interpolateStrings=true) + evaluateCallOutputs(workflowDescriptor, call, hostAbsoluteFilePath, environment.engineFunctions, scopedLookupFunction, interpolateStrings=true) + } else if (rc == 143) { + // Special case to check for SIGTERM exit code - implying abort: + Failure(new TaskAbortedException()) } else { Failure(new Throwable(s"Workflow ${workflowDescriptor.id}: return code $rc for command: $instantiatedCommandLine\n\nFull command was: ${argv.mkString(" ")}")) } diff --git a/src/main/scala/cromwell/engine/backend/local/LocalEngineFunctions.scala b/src/main/scala/cromwell/engine/backend/local/LocalEngineFunctions.scala index 1dbd4569a3c..b027f6f8c9c 100644 --- a/src/main/scala/cromwell/engine/backend/local/LocalEngineFunctions.scala +++ b/src/main/scala/cromwell/engine/backend/local/LocalEngineFunctions.scala @@ -3,13 +3,15 @@ package cromwell.engine.backend.local import java.io.File import java.nio.file.Paths -import cromwell.binding.types.{WdlArrayType, WdlStringType} +import cromwell.binding.WdlStandardLibraryFunctions +import cromwell.binding.types.{WdlArrayType, WdlFileType, WdlMapType, WdlStringType} import cromwell.binding.values._ -import cromwell.engine.EngineFunctions -import cromwell.util.FileUtil.{EnhancedPath, EnhancedFile} -import scala.util.{Success, Failure, Try} +import cromwell.util.FileUtil +import cromwell.util.FileUtil.{EnhancedFile, EnhancedPath} -class LocalEngineFunctions(executionContext: TaskExecutionContext) extends EngineFunctions { +import scala.util.{Failure, Success, Try} + +class LocalEngineFunctions(executionContext: LocalTaskExecutionContext) extends WdlStandardLibraryFunctions { /** * Read the entire contents of a file from the specified `WdlValue`, where the file can be @@ -27,6 +29,22 @@ class LocalEngineFunctions(executionContext: TaskExecutionContext) extends Engin } } + override protected def stdout(params: Seq[Try[WdlValue]]): Try[WdlFile] = { + if (params.nonEmpty) { + Failure(new UnsupportedOperationException("stdout() takes zero parameters")) + } else { + Success(WdlFile(executionContext.stdout.toAbsolutePath.toString)) + } + } + + override protected def stderr(params: Seq[Try[WdlValue]]): Try[WdlFile] = { + if (params.nonEmpty) { + Failure(new UnsupportedOperationException("stderr() takes zero parameters")) + } else { + Success(WdlFile(executionContext.stderr.toAbsolutePath.toString)) + } + } + override protected def read_lines(params: Seq[Try[WdlValue]]): Try[WdlArray] = { for { singleArgument <- extractSingleArgument(params) @@ -34,14 +52,13 @@ class LocalEngineFunctions(executionContext: TaskExecutionContext) extends Engin } yield WdlArray(WdlArrayType(WdlStringType), lines) } - /** - * Try to read a string from the file referenced by the specified `WdlValue`. - */ - override protected def read_string(params: Seq[Try[WdlValue]]): Try[WdlString] = { + override protected def read_map(params: Seq[Try[WdlValue]]): Try[WdlMap] = { for { singleArgument <- extractSingleArgument(params) - string = fileContentsToString(singleArgument) - } yield WdlString(string.stripSuffix("\n")) + if singleArgument.wdlType == WdlFileType + contents <- Success(Paths.get(singleArgument.asInstanceOf[WdlFile].valueString).slurp) + wdlMap <- WdlMap.fromTsv(contents) + } yield wdlMap } /** @@ -50,19 +67,35 @@ class LocalEngineFunctions(executionContext: TaskExecutionContext) extends Engin override protected def read_int(params: Seq[Try[WdlValue]]): Try[WdlInteger] = read_string(params).map { s => WdlInteger(s.value.trim.toInt) } - override protected def stdout(params: Seq[Try[WdlValue]]): Try[WdlFile] = { - if (params.nonEmpty) { - Failure(new UnsupportedOperationException("stdout() takes zero parameters")) - } else { - Success(WdlFile(executionContext.stdout.toAbsolutePath.toString)) - } + /** + * Try to read a string from the file referenced by the specified `WdlValue`. + */ + override protected def read_string(params: Seq[Try[WdlValue]]): Try[WdlString] = { + for { + singleArgument <- extractSingleArgument(params) + string = fileContentsToString(singleArgument) + } yield WdlString(string.stripSuffix("\n")) } - override protected def stderr(params: Seq[Try[WdlValue]]): Try[WdlFile] = { - if (params.nonEmpty) { - Failure(new UnsupportedOperationException("stderr() takes zero parameters")) - } else { - Success(WdlFile(executionContext.stderr.toAbsolutePath.toString)) - } + override protected def write_lines(params: Seq[Try[WdlValue]]): Try[WdlFile] = { + for { + singleArgument <- extractSingleArgument(params) + if singleArgument.wdlType.isInstanceOf[WdlArrayType] + tsvSerialized <- singleArgument.asInstanceOf[WdlArray].tsvSerialize + (path, writer) = FileUtil.tempFileAndWriter("array", executionContext.cwd.toFile) + _ <- Try(writer.write(tsvSerialized)) + _ <- Success(writer.close()) + } yield WdlFile(path.toAbsolutePath.toString) + } + + override protected def write_map(params: Seq[Try[WdlValue]]): Try[WdlFile] = { + for { + singleArgument <- extractSingleArgument(params) + if singleArgument.wdlType.isInstanceOf[WdlMapType] + tsvSerialized <- singleArgument.asInstanceOf[WdlMap].tsvSerialize + (path, writer) = FileUtil.tempFileAndWriter("map", executionContext.cwd.toFile) + _ <- Try(writer.write(tsvSerialized)) + _ <- Success(writer.close()) + } yield WdlFile(path.toAbsolutePath.toString) } } diff --git a/src/main/scala/cromwell/engine/backend/local/LocalTaskExecutionContext.scala b/src/main/scala/cromwell/engine/backend/local/LocalTaskExecutionContext.scala new file mode 100644 index 00000000000..8d607065be0 --- /dev/null +++ b/src/main/scala/cromwell/engine/backend/local/LocalTaskExecutionContext.scala @@ -0,0 +1,9 @@ +package cromwell.engine.backend.local + +import java.nio.file.{Path, Paths} + +import cromwell.engine.backend.TaskExecutionContext + +case class LocalTaskExecutionContext(workflowRoot: Path, stdout: Path, stderr: Path, cwd: Path = Paths.get(".")) extends TaskExecutionContext { + override def engineFunctions: LocalEngineFunctions = new LocalEngineFunctions(this) +} diff --git a/src/main/scala/cromwell/engine/backend/local/TaskExecutionContext.scala b/src/main/scala/cromwell/engine/backend/local/TaskExecutionContext.scala deleted file mode 100644 index 81d10e954dd..00000000000 --- a/src/main/scala/cromwell/engine/backend/local/TaskExecutionContext.scala +++ /dev/null @@ -1,6 +0,0 @@ -package cromwell.engine.backend.local - -import java.nio.file.{Path, Paths} - -/* This is just an example */ -case class TaskExecutionContext(stdout: Path, stderr: Path, cwd: Path = Paths.get(".")) diff --git a/src/main/scala/cromwell/engine/db/DataAccess.scala b/src/main/scala/cromwell/engine/db/DataAccess.scala index 068d3a92dda..17e5b88bdaa 100644 --- a/src/main/scala/cromwell/engine/db/DataAccess.scala +++ b/src/main/scala/cromwell/engine/db/DataAccess.scala @@ -1,9 +1,9 @@ package cromwell.engine.db -import cromwell.binding.values.WdlValue import cromwell.binding._ +import cromwell.binding.values.WdlValue import cromwell.engine.backend.Backend -import cromwell.engine.{SymbolStoreEntry, WorkflowId, WorkflowState} +import cromwell.engine.{WorkflowId, SymbolStoreEntry, WorkflowState} import scala.concurrent.duration.Duration import scala.concurrent.{Await, Future} diff --git a/src/main/scala/cromwell/engine/db/slick/ExecutionComponent.scala b/src/main/scala/cromwell/engine/db/slick/ExecutionComponent.scala index c43ebd570fb..034a36c3b88 100644 --- a/src/main/scala/cromwell/engine/db/slick/ExecutionComponent.scala +++ b/src/main/scala/cromwell/engine/db/slick/ExecutionComponent.scala @@ -4,6 +4,7 @@ case class Execution ( workflowExecutionId: Int, callFqn: String, + index: Int, status: String, executionId: Option[Int] = None ) @@ -20,9 +21,11 @@ trait ExecutionComponent { def callFqn = column[String]("CALL_FQN") + def index = column[Int]("INDEX") + def status = column[String]("STATUS") - override def * = (workflowExecutionId, callFqn, status, executionId.?) <> + override def * = (workflowExecutionId, callFqn, index, status, executionId.?) <> (Execution.tupled, Execution.unapply) def workflowExecution = foreignKey( diff --git a/src/main/scala/cromwell/engine/db/slick/RunMysql.scala b/src/main/scala/cromwell/engine/db/slick/RunMysql.scala index ac7d28a3f08..fe798d9615f 100644 --- a/src/main/scala/cromwell/engine/db/slick/RunMysql.scala +++ b/src/main/scala/cromwell/engine/db/slick/RunMysql.scala @@ -2,7 +2,7 @@ package cromwell.engine.db.slick import java.sql.{Connection, DriverManager} -import com.typesafe.config.{ConfigRenderOptions, ConfigFactory} +import com.typesafe.config.{ConfigFactory, ConfigRenderOptions} import slick.jdbc.SimpleJdbcAction import scala.collection.JavaConverters._ diff --git a/src/main/scala/cromwell/engine/db/slick/SlickDataAccess.scala b/src/main/scala/cromwell/engine/db/slick/SlickDataAccess.scala index 82a70a5ccd8..1c0f1ba1353 100644 --- a/src/main/scala/cromwell/engine/db/slick/SlickDataAccess.scala +++ b/src/main/scala/cromwell/engine/db/slick/SlickDataAccess.scala @@ -7,7 +7,8 @@ import javax.sql.rowset.serial.SerialClob import _root_.slick.util.ConfigExtensionMethods._ import com.typesafe.config.{Config, ConfigFactory, ConfigValueFactory} import cromwell.binding._ -import cromwell.binding.types.WdlType +import cromwell.binding.types.{WdlPrimitiveType, WdlType} +import cromwell.binding.values.WdlValue import cromwell.engine._ import cromwell.engine.backend.Backend import cromwell.engine.backend.jes.JesBackend @@ -24,7 +25,7 @@ object SlickDataAccess { type IoValue = String val IoInput = "INPUT" val IoOutput = "OUTPUT" - val IterationNone = -1 // "It's a feature" https://bugs.mysql.com/bug.php?id=8173 + val IndexNone = -1 // "It's a feature" https://bugs.mysql.com/bug.php?id=8173 implicit class DateToTimestamp(val date: Date) extends AnyVal { def toTimestamp = new Timestamp(date.getTime) @@ -120,6 +121,17 @@ class SlickDataAccess(databaseConfig: Config, val dataAccess: DataAccessComponen } } + private def wdlValueToDbValue(v: WdlValue): String = v.wdlType match { + case p: WdlPrimitiveType => v.valueString + case o => v.toWdlString + } + + private def dbEntryToWdlValue(dbValue: String, wdlType: WdlType): WdlValue = wdlType match { + // .get here is because we trust the value in the database is coercible to the given type + case p: WdlPrimitiveType => p.coerceRawValue(dbValue).get + case o => wdlType.fromWdlString(dbValue) + } + override def shutdown() = database.shutdown // Run action with an outer transaction @@ -171,10 +183,10 @@ class SlickDataAccess(databaseConfig: Config, val dataAccess: DataAccessComponen workflowExecution.workflowExecutionId.get, symbol.key.scope, symbol.key.name, - symbol.key.iteration.getOrElse(IterationNone), + symbol.key.index.getOrElse(IndexNone), if (symbol.isInput) IoInput else IoOutput, symbol.wdlType.toWdlString, - symbol.wdlValue.map(_.toWdlString.toClob)) + symbol.wdlValue.map(v => wdlValueToDbValue(v).toClob)) } } @@ -194,6 +206,7 @@ class SlickDataAccess(databaseConfig: Config, val dataAccess: DataAccessComponen new Execution( workflowExecution.workflowExecutionId.get, call.fullyQualifiedName, + IndexNone, ExecutionStatus.NotStarted.toString) // Depending on the backend, insert a job specific row @@ -220,7 +233,7 @@ class SlickDataAccess(databaseConfig: Config, val dataAccess: DataAccessComponen val action = for { workflowExecutionStatusOption <- dataAccess.workflowExecutionStatusesByWorkflowExecutionUuid( - workflowId.toString).result.headOption + workflowId.id.toString).result.headOption workflowState = workflowExecutionStatusOption map WorkflowState.fromString } yield workflowState @@ -233,7 +246,7 @@ class SlickDataAccess(databaseConfig: Config, val dataAccess: DataAccessComponen // NOTE: For now, intentionally causes query to error out instead of returning an Map.empty workflowExecutionResult <- dataAccess.workflowExecutionsByWorkflowExecutionUuid( - workflowId.toString).result.head + workflowId.id.toString).result.head // Alternatively, could use a dataAccess.executionCallFqnsAndStatusesByWorkflowExecutionUuid executionCallFqnAndStatusResults <- dataAccess.executionCallFqnsAndStatusesByWorkflowExecutionId( @@ -273,7 +286,7 @@ class SlickDataAccess(databaseConfig: Config, val dataAccess: DataAccessComponen workflowExecutionAuxResult map { workflowExecutionAux => new WorkflowInfo( - UUID.fromString(workflowExecutionResult.workflowExecutionUuid), + WorkflowId.fromString(workflowExecutionResult.workflowExecutionUuid), workflowExecutionAux.wdlSource.toRawString, workflowExecutionAux.jsonInputs.toRawString) } @@ -376,11 +389,11 @@ class SlickDataAccess(databaseConfig: Config, val dataAccess: DataAccessComponen new SymbolStoreKey( symbolResult.scope, symbolResult.name, - Option(symbolResult.iteration).filterNot(_ == IterationNone), + Option(symbolResult.index).filterNot(_ == IndexNone), input = symbolResult.io == IoInput // input = true, if db contains "INPUT" ), wdlType, - symbolResult.wdlValue map {value => wdlType.fromWdlString(value.toRawString)} + symbolResult.wdlValue map {v => dbEntryToWdlValue(v.toRawString, wdlType)} ) } @@ -395,9 +408,8 @@ class SlickDataAccess(databaseConfig: Config, val dataAccess: DataAccessComponen } override def getAll(workflowId: WorkflowId): Future[Traversable[SymbolStoreEntry]] = { - val x = dataAccess.allSymbols(workflowId.toString).result val action = for { - symbolResults <- x + symbolResults <- dataAccess.allSymbols(workflowId.toString).result symbolStoreEntries = symbolResults map toSymbolStoreEntry } yield symbolStoreEntries @@ -436,7 +448,6 @@ class SlickDataAccess(databaseConfig: Config, val dataAccess: DataAccessComponen /** Should fail if a value is already set. The keys in the Map are locally qualified names. */ override def setOutputs(workflowId: WorkflowId, call: Call, callOutputs: WorkflowOutputs): Future[Unit] = { - val action = for { workflowExecution <- dataAccess.workflowExecutionsByWorkflowExecutionUuid(workflowId.toString).result.head _ <- dataAccess.symbolsAutoInc ++= callOutputs map { @@ -445,10 +456,10 @@ class SlickDataAccess(databaseConfig: Config, val dataAccess: DataAccessComponen workflowExecution.workflowExecutionId.get, call.fullyQualifiedName, symbolLocallyQualifiedName, - IterationNone, + IndexNone, IoOutput, wdlValue.wdlType.toWdlString, - Option(wdlValue.toWdlString.toClob)) + Option(wdlValueToDbValue(wdlValue).toClob)) } } yield () diff --git a/src/main/scala/cromwell/engine/db/slick/SymbolComponent.scala b/src/main/scala/cromwell/engine/db/slick/SymbolComponent.scala index 7a363483870..d89fea63766 100644 --- a/src/main/scala/cromwell/engine/db/slick/SymbolComponent.scala +++ b/src/main/scala/cromwell/engine/db/slick/SymbolComponent.scala @@ -7,7 +7,7 @@ case class Symbol workflowExecutionId: Int, scope: String, name: String, - iteration: Int, // https://bugs.mysql.com/bug.php?id=8173 + index: Int, // https://bugs.mysql.com/bug.php?id=8173 io: String, wdlType: String, wdlValue: Option[Clob], @@ -28,7 +28,7 @@ trait SymbolComponent { def name = column[String]("NAME") - def iteration = column[Int]("ITERATION") + def index = column[Int]("INDEX") def io = column[String]("IO") @@ -36,14 +36,14 @@ trait SymbolComponent { def wdlValue = column[Option[Clob]]("WDL_VALUE") - override def * = (workflowExecutionId, scope, name, iteration, io, wdlType, wdlValue, symbolId.?) <> + override def * = (workflowExecutionId, scope, name, index, io, wdlType, wdlValue, symbolId.?) <> (Symbol.tupled, Symbol.unapply) def workflowExecution = foreignKey( "FK_SYMBOL_WORKFLOW_EXECUTION_ID", workflowExecutionId, workflowExecutions)(_.workflowExecutionId) def uniqueKey = index("UK_SYM_WORKFLOW_EXECUTION_ID_SCOPE_NAME_ITERATION_IO", - (workflowExecutionId, scope, name, iteration, io), unique = true) + (workflowExecutionId, scope, name, index, io), unique = true) } protected val symbols = TableQuery[Symbols] diff --git a/src/main/scala/cromwell/engine/db/slick/WorkflowExecutionComponent.scala b/src/main/scala/cromwell/engine/db/slick/WorkflowExecutionComponent.scala index dae049711de..1d710b56940 100644 --- a/src/main/scala/cromwell/engine/db/slick/WorkflowExecutionComponent.scala +++ b/src/main/scala/cromwell/engine/db/slick/WorkflowExecutionComponent.scala @@ -1,9 +1,6 @@ package cromwell.engine.db.slick import java.sql.Timestamp -import java.util.UUID - -import slick.dbio.{NoStream, Effect} case class WorkflowExecution ( diff --git a/src/main/scala/cromwell/engine/package.scala b/src/main/scala/cromwell/engine/package.scala index 80fce12d802..fce80c371d4 100644 --- a/src/main/scala/cromwell/engine/package.scala +++ b/src/main/scala/cromwell/engine/package.scala @@ -14,15 +14,30 @@ import cromwell.binding.values.WdlValue * * Internally, this package is built on top of [[cromwell.binding]]. */ - package object engine { - type WorkflowId = UUID + case class WorkflowId(id: UUID) { + override def toString = id.toString + def shortString = id.toString.split("-")(0) + } + + object WorkflowId { + def fromString(id:String): WorkflowId = new WorkflowId(UUID.fromString(id)) + def randomId() = WorkflowId(UUID.randomUUID()) + } + + case class CallReference(workflowName: String, workflowId: WorkflowId, callName: String) { + override def toString = s"UUID(${workflowId.shortString})/$callName" + } + + case class AbortFunction(function: ()=>Unit) + case class IndexedAbortFunction(callReference: CallReference, callAbortFunction: AbortFunction) + case class AbortFunctionRegistration(registrationFunction: AbortFunction=>Unit) sealed trait WorkflowState { def isTerminal: Boolean } - private lazy val workflowStates = Seq(WorkflowSubmitted, WorkflowRunning, WorkflowFailed, WorkflowSucceeded) + private lazy val workflowStates = Seq(WorkflowSubmitted, WorkflowRunning, WorkflowFailed, WorkflowSucceeded, WorkflowAborting, WorkflowAborted) object WorkflowState { def fromString(str: String): WorkflowState = workflowStates.find(_.toString == str).getOrElse( @@ -38,7 +53,12 @@ package object engine { override def toString: String = "Running" override val isTerminal = false } - + + case object WorkflowAborting extends WorkflowState { + override def toString: String = "Aborting" + override val isTerminal = false + } + case object WorkflowFailed extends WorkflowState { override def toString: String = "Failed" override val isTerminal = true @@ -62,7 +82,7 @@ package object engine { def apply(fullyQualifiedName: FullyQualifiedName, wdlValue: WdlValue, input: Boolean): SymbolStoreEntry = { val (scope, name) = splitFqn(fullyQualifiedName) - val key = SymbolStoreKey(scope, name, iteration = None, input) + val key = SymbolStoreKey(scope, name, index = None, input) SymbolStoreEntry(key, wdlValue.wdlType, Some(wdlValue)) } @@ -75,7 +95,7 @@ package object engine { }.toMap } - case class SymbolStoreKey(scope: String, name: String, iteration: Option[Int], input: Boolean) + case class SymbolStoreKey(scope: String, name: String, index: Option[Int], input: Boolean) case class SymbolStoreEntry(key: SymbolStoreKey, wdlType: WdlType, wdlValue: Option[WdlValue]) { def isInput: Boolean = key.input @@ -85,6 +105,6 @@ package object engine { object ExecutionStatus extends Enumeration { type ExecutionStatus = Value - val NotStarted, Starting, Running, Failed, Done = Value + val NotStarted, Starting, Running, Failed, Done, Aborted, Aborting = Value } } diff --git a/src/main/scala/cromwell/engine/workflow/SingleWorkflowRunnerActor.scala b/src/main/scala/cromwell/engine/workflow/SingleWorkflowRunnerActor.scala index 478de17d424..11f41d67bb4 100644 --- a/src/main/scala/cromwell/engine/workflow/SingleWorkflowRunnerActor.scala +++ b/src/main/scala/cromwell/engine/workflow/SingleWorkflowRunnerActor.scala @@ -4,7 +4,6 @@ import akka.actor.FSM.{CurrentState, Transition} import akka.actor.{Actor, ActorRef, Props} import akka.event.Logging import akka.pattern.ask -import akka.util.Timeout import cromwell.binding import cromwell.binding.{WdlJson, WdlSource} import cromwell.engine._ @@ -51,6 +50,7 @@ case class SingleWorkflowRunnerActor(wdlSource: WdlSource, def receive = { case CurrentState(_, state: WorkflowState) if state.isTerminal => handleTermination(state) case Transition(_, _, state: WorkflowState) if state.isTerminal => handleTermination(state) + case Transition(_, _, state: WorkflowState) => log.info(s"$tag: transitioning to $state") case CurrentState(_, state: WorkflowState) => log.info(s"$tag: received CurrentState($state)") case m => log.warning(s"$tag: received unexpected message: $m") } diff --git a/src/main/scala/cromwell/engine/workflow/ValidateActor.scala b/src/main/scala/cromwell/engine/workflow/ValidateActor.scala index 878c11b377f..a513d0dab10 100644 --- a/src/main/scala/cromwell/engine/workflow/ValidateActor.scala +++ b/src/main/scala/cromwell/engine/workflow/ValidateActor.scala @@ -1,6 +1,6 @@ package cromwell.engine.workflow -import akka.actor.{ActorRef, Actor, Props} +import akka.actor.{Actor, ActorRef, Props} import com.typesafe.scalalogging.LazyLogging import cromwell.binding._ import cromwell.webservice.PerRequest.RequestComplete diff --git a/src/main/scala/cromwell/engine/workflow/WorkflowActor.scala b/src/main/scala/cromwell/engine/workflow/WorkflowActor.scala index 2ecf996795c..732f13f4da6 100644 --- a/src/main/scala/cromwell/engine/workflow/WorkflowActor.scala +++ b/src/main/scala/cromwell/engine/workflow/WorkflowActor.scala @@ -1,10 +1,11 @@ package cromwell.engine.workflow -import akka.actor.{FSM, LoggingFSM, Props} +import akka.actor.{InvalidMessageException, FSM, LoggingFSM, Props} import akka.event.Logging import akka.pattern.pipe import cromwell.binding._ import cromwell.binding.values.{WdlObject, WdlValue} +import cromwell.engine.ExecutionStatus.ExecutionStatus import cromwell.engine._ import cromwell.engine.backend.Backend import cromwell.engine.db.DataAccess.WorkflowInfo @@ -25,6 +26,8 @@ object WorkflowActor { case object Complete extends WorkflowActorMessage case object GetFailureMessage extends WorkflowActorMessage case object GetOutputs extends WorkflowActorMessage + case object AbortWorkflow extends WorkflowActorMessage + case class AbortComplete(call: Call) extends WorkflowActorMessage case class CallStarted(call: Call) extends WorkflowActorMessage case class CallCompleted(call: Call, callOutputs: CallOutputs) extends WorkflowActorMessage case class CallFailed(call: Call, failure: String) extends WorkflowActorMessage @@ -40,6 +43,11 @@ object WorkflowActor { val DatabaseTimeout = 5 seconds type ExecutionStore = Map[Call, ExecutionStatus.Value] + + val TerminalStates = Vector(ExecutionStatus.Failed, ExecutionStatus.Done, ExecutionStatus.Aborted) + def isExecutionStateFinished(es: ExecutionStatus): Boolean = { + TerminalStates contains es + } } case class WorkflowActor(workflow: WorkflowDescriptor, @@ -103,6 +111,13 @@ case class WorkflowActor(workflow: WorkflowDescriptor, persistStatus(call, ExecutionStatus.Failed) goto(WorkflowFailed) using FailureMessage(failure) case Event(Complete, NoFailureMessage) => goto(WorkflowSucceeded) + case Event(AbortComplete(call), NoFailureMessage) => + // Something funky's going on if aborts are coming through while the workflow's still running. But don't second-guess + // by transitioning the whole workflow - the message is either still in the queue or this command was maybe + // cancelled by some external system. + persistStatus(call, ExecutionStatus.Aborted) + log.warning(s"Call ${call.name} was aborted but the workflow should still be running.") + stay() } when(WorkflowFailed) { @@ -115,6 +130,23 @@ case class WorkflowActor(workflow: WorkflowDescriptor, // We're supporting GetOutputs for all states, so there's nothing particular to do here when(WorkflowSucceeded)(FSM.NullFunction) + when(WorkflowAborting) { + case Event(AbortComplete(call), NoFailureMessage) => + persistStatus(call, ExecutionStatus.Aborted) + if (isWorkflowAborted) goto(WorkflowAborted) using NoFailureMessage else stay() + case Event(CallFailed(call, failure), NoFailureMessage) => + persistStatus(call, ExecutionStatus.Failed) + if (isWorkflowAborted) goto(WorkflowAborted) using NoFailureMessage else stay() + case Event(CallCompleted(call, outputs), NoFailureMessage) => + awaitCallComplete(call, outputs) + if (isWorkflowAborted) goto(WorkflowAborted) using NoFailureMessage else stay() + case m => + log.error("Unexpected message in Aborting state: " + m.getClass.getSimpleName) + if (isWorkflowAborted) goto(WorkflowAborted) using NoFailureMessage else stay() + } + + when(WorkflowAborted)(FSM.NullFunction) + whenUnhandled { case Event(GetOutputs, _) => // NOTE: This is currently only used by tests @@ -123,6 +155,9 @@ case class WorkflowActor(workflow: WorkflowDescriptor, val futureOutputs = dataAccess.getOutputs(workflow.id) map SymbolStoreEntry.toWorkflowOutputs futureOutputs pipeTo sender stay() + case Event(AbortWorkflow, _) => + context.children foreach { _ ! CallActor.AbortCall } + goto(WorkflowAborting) using NoFailureMessage case Event(e, _) => log.debug(s"$tag received unhandled event $e while in state $stateName") stay() @@ -369,4 +404,6 @@ case class WorkflowActor(workflow: WorkflowDescriptor, } private def isWorkflowDone: Boolean = executionStore.forall(_._2 == ExecutionStatus.Done) + + private def isWorkflowAborted: Boolean = executionStore forall { x => isExecutionStateFinished(x._2) || x._2 == ExecutionStatus.NotStarted } } diff --git a/src/main/scala/cromwell/engine/workflow/WorkflowManagerActor.scala b/src/main/scala/cromwell/engine/workflow/WorkflowManagerActor.scala index 0c3f1192a09..3fd30d8a001 100644 --- a/src/main/scala/cromwell/engine/workflow/WorkflowManagerActor.scala +++ b/src/main/scala/cromwell/engine/workflow/WorkflowManagerActor.scala @@ -70,8 +70,13 @@ class WorkflowManagerActor(dataAccess: DataAccess, backend: Backend) extends Act case SubmitWorkflow(wdlSource, wdlJson, inputs) => submitWorkflow(wdlSource, wdlJson, inputs, maybeWorkflowId = None) pipeTo sender case WorkflowStatus(id) => dataAccess.getWorkflowState(id) pipeTo sender - // TODO actually attempt to abort workflow - case WorkflowAbort(id) => sender ! Option(WorkflowAborted) + case WorkflowAbort(id) => + workflowStore.toMap.get(id) match { + case Some(x) => + x ! WorkflowActor.AbortWorkflow + sender ! Some(WorkflowAborting) + case None => sender ! None + } case Shutdown => context.system.shutdown() case WorkflowOutputs(id) => workflowOutputs(id) pipeTo sender case CallOutputs(workflowId, callName) => callOutputs(workflowId, callName) pipeTo sender @@ -141,14 +146,14 @@ class WorkflowManagerActor(dataAccess: DataAccess, backend: Backend) extends Act } private def workflowStdoutStderr(workflowId: WorkflowId): Future[Map[FullyQualifiedName, StdoutStderr]] = { - def logMapFromStatusMap(statusMap: Map[FullyQualifiedName, ExecutionStatus]): Try[Map[LocallyQualifiedName, StdoutStderr]] = { + def logMapFromStatusMap(statusMap: Map[FullyQualifiedName, ExecutionStatus]): Try[Map[FullyQualifiedName, StdoutStderr]] = { Try { val callsToPaths = for { (call, status) <- statusMap.toSeq if Set(ExecutionStatus.Done, ExecutionStatus.Failed).contains(status) (wf, callLqn) = assertCallFqnWellFormed(call).get callStandardOutput = backend.stdoutStderr(workflowId, wf, callLqn) - } yield callLqn -> callStandardOutput + } yield call -> callStandardOutput callsToPaths.toMap } } @@ -162,7 +167,7 @@ class WorkflowManagerActor(dataAccess: DataAccess, backend: Backend) extends Act private def submitWorkflow(wdlSource: WdlSource, wdlJson: WdlJson, inputs: WorkflowRawInputs, maybeWorkflowId: Option[WorkflowId]): Future[WorkflowId] = { - val workflowId = maybeWorkflowId.getOrElse(UUID.randomUUID()) + val workflowId: WorkflowId = maybeWorkflowId.getOrElse(WorkflowId.randomId()) log.info(s"$tag submitWorkflow input id = $maybeWorkflowId, effective id = $workflowId") val futureId = for { eventualNamespace <- Future(NamespaceWithWorkflow.load(wdlSource, BackendType)) diff --git a/src/main/scala/cromwell/logging/CromwellLogger.scala b/src/main/scala/cromwell/logging/CromwellLogger.scala index e25fe5c736d..1aceaa589f8 100644 --- a/src/main/scala/cromwell/logging/CromwellLogger.scala +++ b/src/main/scala/cromwell/logging/CromwellLogger.scala @@ -5,8 +5,6 @@ import ch.qos.logback.classic.spi.ILoggingEvent import ch.qos.logback.core.{ConsoleAppender, LayoutBase} import cromwell.util.TerminalUtil -import scala.collection.JavaConverters._ - class TerminalLayout extends LayoutBase[ILoggingEvent] { def doLayout(event: ILoggingEvent): String = { val level = event.getLevel match { diff --git a/src/main/scala/cromwell/util/FileUtil.scala b/src/main/scala/cromwell/util/FileUtil.scala index ef6d549b5c5..d38665ecc94 100644 --- a/src/main/scala/cromwell/util/FileUtil.scala +++ b/src/main/scala/cromwell/util/FileUtil.scala @@ -3,6 +3,8 @@ package cromwell.util import java.io.{BufferedWriter, File, FileWriter, Writer} import java.nio.file.Path +import scala.util.{Failure, Success, Try} + object FileUtil { /** Build a temp file with the specified base name and an associated writer, * return the tuple of both. */ @@ -10,6 +12,14 @@ object FileUtil { File.createTempFile(baseName, ".tmp", directory).toPath.fileAndWriter } + def parseTsv(tsv: String): Try[Array[Array[String]]] = { + val table = tsv.split("\n").map(_.split("\t")) + table.map(_.size).toSet match { + case s if s.size > 1 => Failure(new UnsupportedOperationException("TSV is not uniform")) + case _ => Success(table) + } + } + implicit class FlushingAndClosingWriter(writer: Writer) { /** Convenience method to flush and close in one shot. */ def flushAndClose() = { diff --git a/src/main/scala/cromwell/util/WriteOnceStore.scala b/src/main/scala/cromwell/util/WriteOnceStore.scala index cded084cec6..aa09090027f 100644 --- a/src/main/scala/cromwell/util/WriteOnceStore.scala +++ b/src/main/scala/cromwell/util/WriteOnceStore.scala @@ -1,7 +1,7 @@ package cromwell.util import scala.collection.concurrent.TrieMap -import scala.util.{Success, Failure, Try} +import scala.util.{Failure, Success, Try} class WriteOnceStore[K, V] { private val writeOnceStore = new TrieMap[K, V]() diff --git a/src/main/scala/cromwell/util/google/GoogleCloudStorage.scala b/src/main/scala/cromwell/util/google/GoogleCloudStorage.scala index 296ce660354..5ca455e5644 100644 --- a/src/main/scala/cromwell/util/google/GoogleCloudStorage.scala +++ b/src/main/scala/cromwell/util/google/GoogleCloudStorage.scala @@ -2,15 +2,14 @@ package cromwell.util.google import java.io._ import java.math.BigInteger -import java.nio.file.Path import com.google.api.client.auth.oauth2.Credential import com.google.api.client.http.{HttpTransport, InputStreamContent} import com.google.api.client.json.JsonFactory import com.google.api.client.util.DateTime import com.google.api.services.storage.Storage -import com.google.api.services.storage.model.{StorageObject, Bucket} import com.google.api.services.storage.model.Bucket.Owner +import com.google.api.services.storage.model.{Bucket, StorageObject} import cromwell.util.google.GoogleCloudStorage.GcsBucketInfo object GoogleCloudStorage { @@ -36,7 +35,13 @@ case class GoogleCloudStorage(client: Storage) { // See comment in uploadObject re small files. Here, define small as 2MB or lower: private val smallFileSizeLimit: Long = 2000000 - def uploadObject(gcsPath: GoogleCloudStoragePath, inputStream: InputStream, byteCount: Long) = { + def uploadObject(gcsPath: GoogleCloudStoragePath, fileContent: String): Unit = { + val fileBytes = fileContent.getBytes + val bais = new ByteArrayInputStream(fileBytes) + uploadObject(gcsPath, bais, fileBytes.length) + } + + def uploadObject(gcsPath: GoogleCloudStoragePath, inputStream: InputStream, byteCount: Long): Unit = { val mediaContent: InputStreamContent = new InputStreamContent("application/octet-stream", inputStream) mediaContent.setLength(byteCount) diff --git a/src/main/scala/cromwell/util/google/GoogleCredentialFactory.scala b/src/main/scala/cromwell/util/google/GoogleCredentialFactory.scala index a65ba10fa4a..167d6584e4d 100644 --- a/src/main/scala/cromwell/util/google/GoogleCredentialFactory.scala +++ b/src/main/scala/cromwell/util/google/GoogleCredentialFactory.scala @@ -1,19 +1,17 @@ package cromwell.util.google import java.io.{File, FileInputStream, InputStreamReader} -import java.nio.file.{Paths, Path} -import java.security.PrivateKey +import java.nio.file.Paths import com.google.api.client.auth.oauth2.Credential import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp -import com.google.api.client.googleapis.auth.oauth2.GoogleCredential.Builder -import com.google.api.client.googleapis.auth.oauth2.{GoogleCredential, GoogleAuthorizationCodeFlow, GoogleClientSecrets} +import com.google.api.client.googleapis.auth.oauth2.{GoogleAuthorizationCodeFlow, GoogleClientSecrets, GoogleCredential} import com.google.api.client.googleapis.extensions.java6.auth.oauth2.GooglePromptReceiver import com.google.api.client.http.HttpTransport import com.google.api.client.json.JsonFactory import com.google.api.client.util.store.FileDataStoreFactory -import com.google.api.services.storage.StorageScopes import com.typesafe.config.{Config, ConfigFactory} + import scala.collection.JavaConverters._ object GoogleCredentialFactory { diff --git a/src/main/scala/cromwell/webservice/ApiDataModels.scala b/src/main/scala/cromwell/webservice/ApiDataModels.scala index f5aa268f364..9fd101c30bf 100644 --- a/src/main/scala/cromwell/webservice/ApiDataModels.scala +++ b/src/main/scala/cromwell/webservice/ApiDataModels.scala @@ -70,4 +70,4 @@ case class CallStdoutStderrResponse id: String, @(ApiModelProperty@field)(required = true, value = "The fully qualified name of the call") logs: Map[String, StdoutStderr] - ) +) diff --git a/src/main/scala/cromwell/webservice/CromwellApiService.scala b/src/main/scala/cromwell/webservice/CromwellApiService.scala index 6243aff5a70..a0350aafccc 100644 --- a/src/main/scala/cromwell/webservice/CromwellApiService.scala +++ b/src/main/scala/cromwell/webservice/CromwellApiService.scala @@ -6,6 +6,7 @@ import javax.ws.rs.Path import akka.actor.{Actor, ActorRef, ActorRefFactory, Props} import com.typesafe.config.Config import com.wordnik.swagger.annotations._ +import cromwell.engine.WorkflowId import cromwell.engine.workflow.ValidateActor import spray.http.StatusCodes import spray.json._ @@ -97,7 +98,7 @@ trait CromwellApiService extends HttpService with PerRequestCreator { def queryRoute = path("workflows" / Segment / Segment / "status") { (version, id) => get { - Try(UUID.fromString(id)) match { + Try(WorkflowId.fromString(id)) match { case Success(workflowId) => requestContext => perRequest(requestContext, CromwellApiHandler.props(workflowManager), CromwellApiHandler.WorkflowStatus(workflowId)) case Failure(ex) => @@ -127,7 +128,7 @@ trait CromwellApiService extends HttpService with PerRequestCreator { def abortRoute = path("workflows" / Segment / Segment / "abort") { (version, id) => post { - Try(UUID.fromString(id)) match { + Try(WorkflowId.fromString(id)) match { case Success(workflowId) => requestContext => perRequest(requestContext, CromwellApiHandler.props(workflowManager), CromwellApiHandler.WorkflowAbort(workflowId)) case Failure(ex) => @@ -228,7 +229,7 @@ trait CromwellApiService extends HttpService with PerRequestCreator { def workflowOutputsRoute = path("workflows" / Segment / Segment / "outputs") { (version, id) => get { - Try(UUID.fromString(id)) match { + Try(WorkflowId.fromString(id)) match { case Success(workflowId) => requestContext => perRequest(requestContext, CromwellApiHandler.props(workflowManager), CromwellApiHandler.WorkflowOutputs(workflowId)) case Failure(ex) => @@ -260,7 +261,7 @@ trait CromwellApiService extends HttpService with PerRequestCreator { )) def callOutputsRoute = path("workflows" / Segment / Segment / "outputs" / Segment) { (version, workflowId, callFqn) => - Try(UUID.fromString(workflowId)) match { + Try(WorkflowId.fromString(workflowId)) match { case Success(w) => // This currently does not attempt to parse the call name for conformation to any pattern. requestContext => perRequest(requestContext, CromwellApiHandler.props(workflowManager), CromwellApiHandler.CallOutputs(w, callFqn)) @@ -292,7 +293,7 @@ trait CromwellApiService extends HttpService with PerRequestCreator { )) def callStdoutStderrRoute = path("workflows" / Segment / Segment / "logs" / Segment) { (version, workflowId, callFqn) => - Try(UUID.fromString(workflowId)) match { + Try(WorkflowId.fromString(workflowId)) match { case Success(w) => // This currently does not attempt to parse the call name for conformation to any pattern. requestContext => perRequest(requestContext, CromwellApiHandler.props(workflowManager), CromwellApiHandler.CallStdoutStderr(w, callFqn)) @@ -322,7 +323,7 @@ trait CromwellApiService extends HttpService with PerRequestCreator { )) def workflowStdoutStderrRoute = path("workflows" / Segment / Segment / "logs") { (version, workflowId) => - Try(UUID.fromString(workflowId)) match { + Try(WorkflowId.fromString(workflowId)) match { case Success(w) => requestContext => perRequest(requestContext, CromwellApiHandler.props(workflowManager), CromwellApiHandler.WorkflowStdoutStderr(w)) case Failure(_) => diff --git a/src/main/scala/cromwell/webservice/PerRequest.scala b/src/main/scala/cromwell/webservice/PerRequest.scala index 2e88b016a89..36ac2999255 100644 --- a/src/main/scala/cromwell/webservice/PerRequest.scala +++ b/src/main/scala/cromwell/webservice/PerRequest.scala @@ -1,15 +1,14 @@ package cromwell.webservice -import akka.actor._ import akka.actor.SupervisorStrategy.Stop +import akka.actor.{OneForOneStrategy, _} import cromwell.webservice.PerRequest._ import spray.http.StatusCodes._ +import spray.http._ import spray.httpx.marshalling.ToResponseMarshaller import spray.routing.RequestContext -import akka.actor.OneForOneStrategy -import scala.concurrent.duration._ -import spray.http._ +import scala.concurrent.duration._ import scala.language.postfixOps /** diff --git a/src/main/scala/cromwell/webservice/WorkflowJsonSupport.scala b/src/main/scala/cromwell/webservice/WorkflowJsonSupport.scala index efd8a808d8f..bb8881c69c1 100644 --- a/src/main/scala/cromwell/webservice/WorkflowJsonSupport.scala +++ b/src/main/scala/cromwell/webservice/WorkflowJsonSupport.scala @@ -1,7 +1,7 @@ package cromwell.webservice -import cromwell.binding.values.WdlValueJsonFormatter._ import cromwell.binding.values.WdlFileJsonFormatter._ +import cromwell.binding.values.WdlValueJsonFormatter._ import cromwell.engine.backend.StdoutStderr import spray.json.DefaultJsonProtocol diff --git a/src/test/scala/cromwell/ArrayWorkflowSpec.scala b/src/test/scala/cromwell/ArrayWorkflowSpec.scala index 18cb8b7030d..35dbb3c34e3 100644 --- a/src/test/scala/cromwell/ArrayWorkflowSpec.scala +++ b/src/test/scala/cromwell/ArrayWorkflowSpec.scala @@ -5,7 +5,7 @@ import java.util.UUID import akka.testkit._ import cromwell.CromwellSpec.DockerTest -import cromwell.binding.{WdlFunctions, NamespaceWithWorkflow, WdlNamespace} +import cromwell.binding.{NoFunctions, WdlFunctions, NamespaceWithWorkflow, WdlNamespace} import cromwell.binding.types.{WdlStringType, WdlFileType, WdlArrayType} import cromwell.binding.values.{WdlInteger, WdlArray, WdlFile, WdlString} import cromwell.engine.backend.local.LocalBackend @@ -23,10 +23,11 @@ class ArrayWorkflowSpec extends CromwellTestkitSpec("ArrayWorkflowSpec") { "accept an array for the value" in { runWdlAndAssertOutputs( sampleWdl = SampleWdl.ArrayIO, - EventFilter.info(pattern = s"starting calls: wf.concat, wf.find", occurrences = 1), + EventFilter.info(pattern = s"starting calls: wf.concat, wf.find, wf.serialize", occurrences = 1), expectedOutputs = Map( "wf.count_lines.count" -> WdlInteger(3), - "wf.count_lines_array.count" -> WdlInteger(3) + "wf.count_lines_array.count" -> WdlInteger(3), + "wf.serialize.contents" -> WdlString("str1\nstr2\nstr3") ) ) } @@ -40,9 +41,6 @@ class ArrayWorkflowSpec extends CromwellTestkitSpec("ArrayWorkflowSpec") { val expression = declaration.expression.getOrElse { fail("Expected an expression for declaration 'arr'") } - class NoFunctions extends WdlFunctions { - def getFunction(name: String): WdlFunction = fail("No functions should be called in this test") - } val value = expression.evaluate((s:String) => fail("No lookups"), new NoFunctions()).getOrElse { fail("Expected expression for 'arr' to evaluate") } @@ -52,7 +50,7 @@ class ArrayWorkflowSpec extends CromwellTestkitSpec("ArrayWorkflowSpec") { val catTask = ns.findTask("cat").getOrElse { fail("Expected to find task 'cat'") } - val command = catTask.command.instantiate(Map("files" -> expectedArray)).getOrElse { + val command = catTask.instantiateCommand(Map("files" -> expectedArray)).getOrElse { fail("Expected instantiation to work") } command shouldEqual "cat -s f1 f2 f3" diff --git a/src/test/scala/cromwell/BadTaskOutputWorkflow.scala b/src/test/scala/cromwell/BadTaskOutputWorkflow.scala new file mode 100644 index 00000000000..c9cd2a92b40 --- /dev/null +++ b/src/test/scala/cromwell/BadTaskOutputWorkflow.scala @@ -0,0 +1,21 @@ +package cromwell + +import akka.testkit._ +import cromwell.binding.values.WdlString +import cromwell.engine.WorkflowFailed +import cromwell.util.SampleWdl + +import scala.language.postfixOps + +class BadTaskOutputWorkflowSpec extends CromwellTestkitSpec("BadTaskOutputWorkflowSpec") { + "A task which fails to output a file which we're expecting it to output" should { + "fail and result in a failed workflow" in { + runWdlAndAssertOutputs( + sampleWdl = SampleWdl.BadTaskOutputWdl, + EventFilter.info(pattern = s"starting calls: badExample.bad", occurrences = 1), + expectedOutputs = Map(), + terminalState = WorkflowFailed + ) + } + } +} diff --git a/src/test/scala/cromwell/CromwellTestkitSpec.scala b/src/test/scala/cromwell/CromwellTestkitSpec.scala index 6611b39adba..1cfd05d4f59 100644 --- a/src/test/scala/cromwell/CromwellTestkitSpec.scala +++ b/src/test/scala/cromwell/CromwellTestkitSpec.scala @@ -16,6 +16,9 @@ import cromwell.engine.backend.StdoutStderr import cromwell.engine.backend.local.LocalBackend import cromwell.engine.db.DataAccess import cromwell.engine.workflow.{WorkflowActor, WorkflowManagerActor} +import cromwell.engine.workflow.WorkflowActor +import cromwell.engine.workflow.WorkflowActor._ +import cromwell.engine._ import cromwell.parser.BackendType import cromwell.util.FileUtil._ import cromwell.util.SampleWdl @@ -42,7 +45,8 @@ object CromwellTestkitSpec { |} """.stripMargin - implicit val timeout = Timeout(5 seconds) + val timeoutDuration = 10 seconds + implicit val timeout = Timeout(timeoutDuration) } abstract class CromwellTestkitSpec(name: String) extends TestKit(ActorSystem(name, ConfigFactory.parseString(ConfigText))) @@ -81,7 +85,7 @@ with DefaultTimeout with ImplicitSender with WordSpecLike with Matchers with Bef */ def messageAndWait[M: ClassTag](message: AnyRef)(implicit actorRef: ActorRef): M = { val futureAny = actorRef ? message - Await.result(futureAny.mapTo[M], 5 seconds) + Await.result(futureAny.mapTo[M], timeoutDuration) } /** @@ -90,7 +94,9 @@ with DefaultTimeout with ImplicitSender with WordSpecLike with Matchers with Bef */ def waitForPattern[T](pattern: String, occurrences: Int = 1)(block: => T): T = { EventFilter.info(pattern = pattern, occurrences = occurrences).intercept { - block + within(timeoutDuration) { + block + } } } @@ -117,7 +123,7 @@ with DefaultTimeout with ImplicitSender with WordSpecLike with Matchers with Bef val coercedInputs = namespace.coerceRawInputs(sampleWdl.rawInputs).get val declarations = namespace.staticDeclarationsRecursive(coercedInputs).get val inputs = coercedInputs ++ declarations - WorkflowDescriptor(uuid, namespace, source, sampleWdl.wdlJson, inputs) + WorkflowDescriptor(WorkflowId(uuid), namespace, source, sampleWdl.wdlJson, inputs) } private def buildFsmWorkflowActor(sampleWdl: SampleWdl, runtime: String) = { @@ -128,14 +134,23 @@ with DefaultTimeout with ImplicitSender with WordSpecLike with Matchers with Bef TestActorRef(new WorkflowManagerActor(dataAccess, new LocalBackend)) } - def runWdl(fsm: TestFSMRef[WorkflowState, WorkflowActor.WorkflowFailure, WorkflowActor], eventFilter: EventFilter, expectedOutputs: Map[FullyQualifiedName, WdlValue] = Map.empty): Unit = { + def runWdl(fsm: TestFSMRef[WorkflowState, WorkflowActor.WorkflowFailure, WorkflowActor], + eventFilter: EventFilter, + expectedOutputs: Map[FullyQualifiedName, WdlValue] = Map.empty, + terminalState: WorkflowState = WorkflowSucceeded): Unit = { assert(fsm.stateName == WorkflowSubmitted) eventFilter.intercept { fsm ! WorkflowActor.Start - within(5 seconds) { + within(timeoutDuration) { awaitCond(fsm.stateName == WorkflowRunning) - awaitCond(fsm.stateName.isTerminal) - fsm.stateData should be(WorkflowActor.NoFailureMessage) + awaitCond(fsm.stateName == terminalState) + + if (terminalState == WorkflowSucceeded) + fsm.stateData should be(WorkflowActor.NoFailureMessage) + + if (terminalState == WorkflowFailed) + fsm.stateData.isInstanceOf[WorkflowActor.FailureMessage] shouldEqual true + val outputs = fsm.ask(WorkflowActor.GetOutputs).mapTo[WorkflowOutputs].futureValue expectedOutputs foreach { case (outputFqn, expectedValue) => @@ -156,11 +171,11 @@ with DefaultTimeout with ImplicitSender with WordSpecLike with Matchers with Bef def runWdlWithWorkflowManagerActor(wma: TestActorRef[WorkflowManagerActor], submitMsg: WorkflowManagerActor.SubmitWorkflow, eventFilter: EventFilter, fqn: FullyQualifiedName, stdout: Option[String], stderr: Option[String]) = { eventFilter.intercept { - within(5 seconds) { - val workflowId = Await.result(wma.ask(submitMsg).mapTo[WorkflowId], 5 seconds) - def workflowStatus = Await.result(wma.ask(WorkflowManagerActor.WorkflowStatus(workflowId)).mapTo[Option[WorkflowState]], 5 seconds) + within(timeoutDuration) { + val workflowId = Await.result(wma.ask(submitMsg).mapTo[WorkflowId], timeoutDuration) + def workflowStatus = Await.result(wma.ask(WorkflowManagerActor.WorkflowStatus(workflowId)).mapTo[Option[WorkflowState]], timeoutDuration) awaitCond(workflowStatus.contains(WorkflowSucceeded)) - val standardStreams = Await.result(wma.ask(WorkflowManagerActor.CallStdoutStderr(workflowId, fqn)).mapTo[StdoutStderr], 5 seconds) + val standardStreams = Await.result(wma.ask(WorkflowManagerActor.CallStdoutStderr(workflowId, fqn)).mapTo[StdoutStderr], timeoutDuration) stdout foreach { _ shouldEqual new File(standardStreams.stdout.value).slurp} stderr foreach { _ shouldEqual new File(standardStreams.stderr.value).slurp} } @@ -173,9 +188,9 @@ with DefaultTimeout with ImplicitSender with WordSpecLike with Matchers with Bef runWdl(fsm, eventFilter, expectedOutputs) } - def runWdlAndAssertOutputs(sampleWdl: SampleWdl, eventFilter: EventFilter, runtime: String = "", expectedOutputs: Map[FullyQualifiedName, WdlValue] = Map.empty): Unit = { + def runWdlAndAssertOutputs(sampleWdl: SampleWdl, eventFilter: EventFilter, runtime: String = "", expectedOutputs: Map[FullyQualifiedName, WdlValue] = Map.empty, terminalState: WorkflowState = WorkflowSucceeded): Unit = { val fsm = buildFsmWorkflowActor(sampleWdl, runtime) - runWdl(fsm, eventFilter, expectedOutputs) + runWdl(fsm, eventFilter, expectedOutputs, terminalState) } def runWdlAndAssertStdoutStderr(sampleWdl: SampleWdl, eventFilter: EventFilter, fqn: FullyQualifiedName, runtime: String = "", stdout: Option[String] = None, stderr: Option[String] = None) = { diff --git a/src/test/scala/cromwell/DeclarationWorkflowSpec.scala b/src/test/scala/cromwell/DeclarationWorkflowSpec.scala index 129eed0f634..617d4eb34d7 100644 --- a/src/test/scala/cromwell/DeclarationWorkflowSpec.scala +++ b/src/test/scala/cromwell/DeclarationWorkflowSpec.scala @@ -20,8 +20,8 @@ class DeclarationWorkflowSpec extends CromwellTestkitSpec("DeclarationWorkflowSp "compute inputs properly" in { NamespaceWithWorkflow.load(SampleWdl.DeclarationsWorkflow.wdlSource(runtime=""), BackendType.LOCAL).workflow.inputs shouldEqual Seq( WorkflowInput("two_step.cat.file", WdlFileType, postfixQuantifier = None), - WorkflowInput("two_step.cgrep.pattern", WdlStringType, postfixQuantifier = None), WorkflowInput("two_step.cgrep.str_decl", WdlStringType, postfixQuantifier = None), + WorkflowInput("two_step.cgrep.pattern", WdlStringType, postfixQuantifier = None), WorkflowInput("two_step.flags_suffix", WdlStringType, postfixQuantifier = None) ) } diff --git a/src/test/scala/cromwell/MainSpec.scala b/src/test/scala/cromwell/MainSpec.scala index 24f4b53e0cc..c299b16508d 100644 --- a/src/test/scala/cromwell/MainSpec.scala +++ b/src/test/scala/cromwell/MainSpec.scala @@ -63,45 +63,48 @@ class MainSpec extends FlatSpec with Matchers { val stream = baos Console.withOut(stream) { val (wdl, _) = wdlAndInputs(ThreeStep) - Main.highlight(Array(wdl)) + Main.highlight(Array(wdl, "html")) } val expected = - s"""\u001b[38;5;214mtask\u001b[0m \u001b[38;5;253mps\u001b[0m { - | command { - | ps - | } - | output { - | \u001b[38;5;33mFile\u001b[0m \u001b[38;5;112mprocs\u001b[0m = \033[38;5;13mstdout\033[0m() - | } - |} - | - |\u001b[38;5;214mtask\u001b[0m \u001b[38;5;253mcgrep\u001b[0m { - | command { - | grep '$${\u001b[38;5;33mString\u001b[0m \u001b[38;5;112mpattern\u001b[0m}' $${\u001b[38;5;33mFile\u001b[0m \u001b[38;5;112min_file\u001b[0m} | wc -l - | } - | output { - | \u001b[38;5;33mInt\u001b[0m \u001b[38;5;112mcount\u001b[0m = \u001b[38;5;13mread_int\u001b[0m(\033[38;5;13mstdout\033[0m()) - | } - |} - | - |\u001b[38;5;214mtask\u001b[0m \u001b[38;5;253mwc\u001b[0m { - | command { - | cat $${\u001b[38;5;33mFile\u001b[0m \u001b[38;5;112min_file\u001b[0m} | wc -l - | } - | output { - | \u001b[38;5;33mInt\u001b[0m \u001b[38;5;112mcount\u001b[0m = \u001b[38;5;13mread_int\u001b[0m(\033[38;5;13mstdout\033[0m()) - | } - |} - | - |\u001b[38;5;214mworkflow\u001b[0m \u001b[38;5;253mthree_step\u001b[0m { - | \u001b[38;5;214mcall\u001b[0m \u001b[38;5;253mps\u001b[0m - | \u001b[38;5;214mcall\u001b[0m \u001b[38;5;253mcgrep\u001b[0m { - | input: in_file=ps.procs - | } - | \u001b[38;5;214mcall\u001b[0m \u001b[38;5;253mwc\u001b[0m { - | input: in_file=ps.procs - | } - |}""".stripMargin + """task ps { + | command { + | ps + | } + | output { + | File procs = stdout() + | } + |} + | + |task cgrep { + | String pattern + | File in_file + | command { + | grep '${pattern}' ${in_file} | wc -l + | } + | output { + | Int count = read_int(stdout()) + | } + |} + | + |task wc { + | File in_file + | command { + | cat ${in_file} | wc -l + | } + | output { + | Int count = read_int(stdout()) + | } + |} + | + |workflow three_step { + | call ps + | call cgrep { + | input: in_file=ps.procs + | } + | call wc { + | input: in_file=ps.procs + | } + |}""".stripMargin stream.toString.stripLineEnd shouldEqual expected } diff --git a/src/test/scala/cromwell/MapWorkflowSpec.scala b/src/test/scala/cromwell/MapWorkflowSpec.scala new file mode 100644 index 00000000000..fef8f25351e --- /dev/null +++ b/src/test/scala/cromwell/MapWorkflowSpec.scala @@ -0,0 +1,88 @@ +package cromwell + +import java.nio.file.Files +import java.util.UUID + +import akka.testkit._ +import cromwell.binding.types.{WdlFileType, WdlIntegerType, WdlMapType, WdlStringType} +import cromwell.binding.values._ +import cromwell.binding.{NamespaceWithWorkflow, NoFunctions, WdlFunctions} +import cromwell.engine.backend.TaskExecutionContext +import cromwell.engine.backend.local.{LocalBackend, LocalEngineFunctions, LocalTaskExecutionContext} +import cromwell.parser.BackendType +import cromwell.util.SampleWdl + +import scala.language.postfixOps +import scala.util.{Success, Try} + +class MapWorkflowSpec extends CromwellTestkitSpec("MapWorkflowSpec") { + val tmpDir = Files.createTempDirectory("MapWorkflowSpec") + val ns = NamespaceWithWorkflow.load(SampleWdl.MapLiteral.wdlSource(""), BackendType.LOCAL) + val expectedMap = WdlMap(WdlMapType(WdlFileType, WdlStringType), Map( + WdlFile("f1") -> WdlString("alice"), + WdlFile("f2") -> WdlString("bob"), + WdlFile("f3") -> WdlString("chuck") + )) + + "A task which contains a parameter " should { + "accept an array for the value" in { + runWdlAndAssertOutputs( + sampleWdl = SampleWdl.MapLiteral, + EventFilter.info(pattern = s"starting calls: wf.read_map, wf.write_map", occurrences = 1), + expectedOutputs = Map( + "wf.read_map.out_map" -> WdlMap(WdlMapType(WdlStringType, WdlIntegerType), Map( + WdlString("x") -> WdlInteger(500), + WdlString("y") -> WdlInteger(600), + WdlString("z") -> WdlInteger(700) + )), + "wf.write_map.contents" -> WdlString("f1\talice\nf2\tbob\nf3\tchuck") + ) + ) + } + } + + "A static Map[File, String] declaration" should { + "be a valid declaration" in { + val declaration = ns.workflow.declarations.find {_.name == "map"}.getOrElse { + fail("Expected declaration 'map' to be found") + } + val expression = declaration.expression.getOrElse { + fail("Expected an expression for declaration 'map'") + } + val value = expression.evaluate((s:String) => fail("No lookups"), new NoFunctions()).getOrElse { + fail("Expected expression for 'map' to evaluate") + } + expectedMap.wdlType.coerceRawValue(value).get shouldEqual expectedMap + } + "be usable as an input" in { + val writeMapTask = ns.findTask("write_map").getOrElse { + fail("Expected to find task 'write_map'") + } + class CannedFunctions extends WdlFunctions { + def write_map(params: Seq[Try[WdlValue]]): Try[WdlFile] = Success(WdlFile("/test/map/path")) + def getFunction(name: String): WdlFunction = name match { + case "write_map" => write_map + case _ => throw new UnsupportedOperationException("Only write_map should be called") + } + } + val command = writeMapTask.instantiateCommand(Map("file_to_name" -> expectedMap), new CannedFunctions).getOrElse { + fail("Expected instantiation to work") + } + command shouldEqual "cat /test/map/path" + } + "Coerce Map[String, String] to Map[String, Int] when running the workflow" in { + val outputs = + runWdlAndAssertOutputs( + buildWorkflowDescriptor(SampleWdl.MapLiteral, runtime="", uuid=UUID.randomUUID()), + eventFilter = EventFilter.info(pattern = s"starting calls: wf.read_map, wf.write_map", occurrences = 1), + expectedOutputs = Map( + "wf.read_map.out_map" -> WdlMap(WdlMapType(WdlStringType, WdlIntegerType), Map( + WdlString("x") -> WdlInteger(500), + WdlString("y") -> WdlInteger(600), + WdlString("z") -> WdlInteger(700) + )) + ) + ) + } + } +} diff --git a/src/test/scala/cromwell/OptionalParamWorkflowSpec.scala b/src/test/scala/cromwell/OptionalParamWorkflowSpec.scala index 06597b0c421..cfa3ed1c40b 100644 --- a/src/test/scala/cromwell/OptionalParamWorkflowSpec.scala +++ b/src/test/scala/cromwell/OptionalParamWorkflowSpec.scala @@ -42,8 +42,10 @@ class OptionalParamWorkflowSpec extends CromwellTestkitSpec("OptionalParamWorkfl "not include that prefix if no value is specified" in { val wf = """ |task find { + | String? pattern + | File root | command { - | find ${File root} ${"-name " pattern?} + | find ${root} ${"-name " + pattern} | } |} | @@ -56,12 +58,12 @@ class OptionalParamWorkflowSpec extends CromwellTestkitSpec("OptionalParamWorkfl fail("Expected to find task 'find'") } - val instantiateWithoutValue = findTask.command.instantiate(Map("root" -> WdlFile("src"))) getOrElse { + val instantiateWithoutValue = findTask.instantiateCommand(Map("root" -> WdlFile("src"))) getOrElse { fail("Expected instantiation to work") } instantiateWithoutValue shouldEqual "find src" - val instantiateWithValue = findTask.command.instantiate(Map( + val instantiateWithValue = findTask.instantiateCommand(Map( "root" -> WdlFile("src"), "pattern" -> WdlString("*.java") )).getOrElse {fail("Expected instantiation to work")} diff --git a/src/test/scala/cromwell/PostfixQuantifierWorkflowSpec.scala b/src/test/scala/cromwell/PostfixQuantifierWorkflowSpec.scala index 253334d865f..f972973ad69 100644 --- a/src/test/scala/cromwell/PostfixQuantifierWorkflowSpec.scala +++ b/src/test/scala/cromwell/PostfixQuantifierWorkflowSpec.scala @@ -8,23 +8,23 @@ import scala.language.postfixOps class PostfixQuantifierWorkflowSpec extends CromwellTestkitSpec("PostfixQuantifierWorkflowSpec") { "A task which contains a parameter with a zero-or-more postfix quantifier" should { - "accept an array for the value" in { + "accept an array of size 3" in { runWdlAndAssertOutputs( sampleWdl = SampleWdl.ZeroOrMorePostfixQuantifierWorkflowWithArrayInput, EventFilter.info(pattern = s"starting calls: postfix.hello", occurrences = 1), expectedOutputs = Map("postfix.hello.greeting" -> WdlString("hello alice,bob,charles")) ) } - "accept a scalar for the value" in { + "accept an array of size 1" in { runWdlAndAssertOutputs( - sampleWdl = SampleWdl.ZeroOrMorePostfixQuantifierWorkflowWithScalarInput, + sampleWdl = SampleWdl.ZeroOrMorePostfixQuantifierWorkflowWithOneElementArrayInput, EventFilter.info(pattern = s"starting calls: postfix.hello", occurrences = 1), expectedOutputs = Map("postfix.hello.greeting" -> WdlString("hello alice")) ) } - "accept no value" in { + "accept an array of size 0" in { runWdlAndAssertOutputs( - sampleWdl = SampleWdl.ZeroOrMorePostfixQuantifierWorkflowWithNoInput, + sampleWdl = SampleWdl.ZeroOrMorePostfixQuantifierWorkflowWithZeroElementArrayInput, EventFilter.info(pattern = s"starting calls: postfix.hello", occurrences = 1), expectedOutputs = Map("postfix.hello.greeting" -> WdlString("hello ")) ) diff --git a/src/test/scala/cromwell/SimpleWorkflowActorSpec.scala b/src/test/scala/cromwell/SimpleWorkflowActorSpec.scala index 0e89945034c..63c34efe50b 100644 --- a/src/test/scala/cromwell/SimpleWorkflowActorSpec.scala +++ b/src/test/scala/cromwell/SimpleWorkflowActorSpec.scala @@ -27,7 +27,7 @@ class SimpleWorkflowActorSpec extends CromwellTestkitSpec("SimpleWorkflowActorSp val namespace = NamespaceWithWorkflow.load(sampleWdl.wdlSource(), BackendType.LOCAL) val rawInputs = rawInputsOverride.getOrElse(sampleWdl.rawInputs) val coercedInputs = namespace.coerceRawInputs(rawInputs).get - val descriptor = WorkflowDescriptor(UUID.randomUUID(), namespace, sampleWdl.wdlSource(), sampleWdl.wdlJson, coercedInputs) + val descriptor = WorkflowDescriptor(WorkflowId(UUID.randomUUID()), namespace, sampleWdl.wdlSource(), sampleWdl.wdlJson, coercedInputs) TestFSMRef(new WorkflowActor(descriptor, new LocalBackend, dataAccess)) } diff --git a/src/test/scala/cromwell/binding/ParameterCommandPartSpec.scala b/src/test/scala/cromwell/binding/ParameterCommandPartSpec.scala index 250a3ae0eba..5816d24f7b5 100644 --- a/src/test/scala/cromwell/binding/ParameterCommandPartSpec.scala +++ b/src/test/scala/cromwell/binding/ParameterCommandPartSpec.scala @@ -7,96 +7,88 @@ import cromwell.parser.BackendType import cromwell.parser.WdlParser.SyntaxError import org.scalatest.{FlatSpec, Matchers} -class ParameterCommandPartSpec extends FlatSpec with Matchers { - val param1 = ParameterCommandPart(WdlStringType, "name", prefix=None, attributes=Map.empty[String, String]) - val param2 = ParameterCommandPart(WdlStringType, "name", prefix=Some("-p "), attributes=Map.empty[String, String]) - val param3 = ParameterCommandPart(WdlStringType, "name", prefix=Some("-p "), attributes=Map("sep" -> ","), postfixQuantifier=Some("*")) - val param4 = ParameterCommandPart(WdlIntegerType, "id", prefix=None, attributes=Map("default" -> "1")) - - "command parameter" should "stringify correctly" in { - param1.toString shouldEqual "${String name}" - } - - "command parameter instantiation" should "prepend a prefix is specified" in { - param2.instantiate(Map("name" -> WdlString("foobar"))) shouldEqual "-p foobar" - } - - it should "combine elements together if * postfix quantifier specified" in { - val array = WdlArray(WdlArrayType(WdlStringType), Seq(WdlString("foo"), WdlString("bar"), WdlString("baz"))) - param3.instantiate(Map("name" -> array)) shouldEqual "-p foo,bar,baz" - } +import scala.util.Failure - it should "ignore the default value if a value is specified" in { - param4.instantiate(Map("id" -> WdlInteger(99))) shouldEqual "99" +class ParameterCommandPartSpec extends FlatSpec with Matchers { + val wdl = + """task param_test { + | String a + | String b + | Array[String] c + | Int? d + | + | command <<< + | ./binary ${a} ${"-p " + b} ${sep="," c} ${default=9 d} + | >>> + |} + | + |workflow wf {call param_test} + """.stripMargin + val namespace = WdlNamespace.load(wdl, BackendType.LOCAL) + val task = namespace.tasks find {_.name == "param_test"} getOrElse { + fail("task 'param_test' not found") } - it should "use the default value if a value is not specified" in { - param4.instantiate(Map.empty[FullyQualifiedName, WdlValue]) shouldEqual "1" + val paramsByName = task.commandTemplate.collect {case p: ParameterCommandPart => p}.map {p => p} + "Template variables" should "Stringify correctly" in { + paramsByName.size shouldEqual 4 + paramsByName(0).toString shouldEqual "${a}" + paramsByName(1).toString shouldEqual "${\"-p \" + b}" + paramsByName(2).toString shouldEqual "${sep=',' c}" + paramsByName(3).toString shouldEqual "${default='9' d}" } - it should "raise exception if it can't instantiate the parameter" in { - try { - param1.instantiate(Map.empty[String, WdlValue]) - fail("Expected an exception") - } catch { - case _: UnsupportedOperationException => // expected - } + "Command instantiation" should "succeed if given valid inputs" in { + task.instantiateCommand(Map( + "a" -> WdlString("a_val"), + "b" -> WdlString("b_val"), + "c" -> WdlArray(WdlArrayType(WdlStringType), Seq(WdlString("c0"), WdlString("c1"), WdlString("c2"))), + "d" -> WdlInteger(1) + )).get shouldEqual "./binary a_val -p b_val c0,c1,c2 1" } - it should "raise exception if a parameter is a WdlExpression" in { - try { - param1.instantiate(Map("name" -> WdlExpression.fromString("1+1"))) - fail("Expected an exception") - } catch { - case _: UnsupportedOperationException => // expected - } + it should "succeed if omitting an optional input" in { + task.instantiateCommand(Map( + "a" -> WdlString("a_val"), + "b" -> WdlString("b_val"), + "c" -> WdlArray(WdlArrayType(WdlStringType), Seq(WdlString("c0"), WdlString("c1"), WdlString("c2"))) + )).get shouldEqual "./binary a_val -p b_val c0,c1,c2 9" } - it should "raise exception if a parameter not the right type" in { - try { - param1.instantiate(Map("name" -> WdlInteger(2))) - fail("Expected an exception") - } catch { - case _: UnsupportedOperationException => // expected - } + it should "succeed if providing an array with one element" in { + task.instantiateCommand(Map( + "a" -> WdlString("a_val"), + "b" -> WdlString("b_val"), + "c" -> WdlArray(WdlArrayType(WdlStringType), Seq(WdlString("c0"))), + "d" -> WdlInteger(1) + )).get shouldEqual "./binary a_val -p b_val c0 1" } - it should "raise exception if a parameter has a * or + postfix quantifier but no 'sep' attribute set" in { - try { - WdlNamespace.load( - """task test { - | command { ./script ${stuff*} } - |} - """.stripMargin, BackendType.LOCAL) - fail("Expected an exception") - } catch { - case _: SyntaxError => // expected - } + it should "succeed if providing an array with zero elements" in { + task.instantiateCommand(Map( + "a" -> WdlString("a_val"), + "b" -> WdlString("b_val"), + "c" -> WdlArray(WdlArrayType(WdlStringType), Seq()), + "d" -> WdlInteger(1) + )).get shouldEqual "./binary a_val -p b_val 1" } - it should "raise exception if a parameter specifies the 'default' attribute but no ? or * postfix quantifier" in { - try { - WdlNamespace.load( - """task test { - | command { ./script ${default="x" stuff} } - |} - """.stripMargin, BackendType.LOCAL) - fail("Expected an exception") - } catch { - case _: SyntaxError => // expected + it should "raise exception if a required input is missing" in { + task.instantiateCommand(Map("a" -> WdlString("a_val"))) match { + case Failure(f) => // expected + case _ => fail("Expected an exception") } } - it should "raise exception if a parameter specifies the 'default' attribute but no ? or * postfix quantifier (2)" in { - try { - WdlNamespace.load( - """task test { - | command { ./script ${default="x" stuff+} } - |} - """.stripMargin, BackendType.LOCAL) - fail("Expected an exception") - } catch { - case _: SyntaxError => // expected + it should "raise exception if a parameter is an expression" in { + task.instantiateCommand(Map( + "a" -> WdlString("a_val"), + "b" -> WdlExpression.fromString("'a'+'b'"), + "c" -> WdlArray(WdlArrayType(WdlStringType), Seq()), + "d" -> WdlInteger(1) + )) match { + case Failure(f) => // expected + case _ => fail("Expected an exception") } } } diff --git a/src/test/scala/cromwell/binding/RuntimeAttributeSpec.scala b/src/test/scala/cromwell/binding/RuntimeAttributeSpec.scala index f12d7def1a9..6244bacedb4 100644 --- a/src/test/scala/cromwell/binding/RuntimeAttributeSpec.scala +++ b/src/test/scala/cromwell/binding/RuntimeAttributeSpec.scala @@ -21,8 +21,10 @@ object RuntimeAttributeSpec { |} | |task cgrep { + | String pattern + | File in_file | command { - | grep '${pattern}' ${File in_file} | wc -l + | grep '${pattern}' ${in_file} | wc -l | } | output { | Int count = read_int(stdout()) @@ -33,8 +35,9 @@ object RuntimeAttributeSpec { |} | |task wc { + | File in_file | command { - | cat ${File in_file} | wc -l + | cat ${in_file} | wc -l | } | output { | Int count = read_int(stdout()) @@ -59,6 +62,7 @@ object RuntimeAttributeSpec { val WorkflowWithoutRuntime = """ |task hello { + | String addressee | command { | echo "Hello ${addressee}!" | } diff --git a/src/test/scala/cromwell/binding/SameNameParametersSpec.scala b/src/test/scala/cromwell/binding/SameNameParametersSpec.scala index 134ba98734e..3e35b470890 100644 --- a/src/test/scala/cromwell/binding/SameNameParametersSpec.scala +++ b/src/test/scala/cromwell/binding/SameNameParametersSpec.scala @@ -9,17 +9,19 @@ class SameNameParametersSpec extends FlatSpec with Matchers { val namespace1 = NamespaceWithWorkflow.load( """ |task test { - | command { ./script ${String x} ${String x} ${x} } + | String x + | command { ./script ${x} ${x} ${x} } |} |workflow wf { call test } """.stripMargin, BackendType.LOCAL ) + val task = namespace1.findTask("test").get "A task with command that uses the same parameter more than once" should "only count it as one input" in { - namespace1.findTask("test").get.inputs shouldEqual Seq(TaskInput(name="x", wdlType=WdlStringType)) + task.inputs shouldEqual Seq(TaskInput(name="x", wdlType=WdlStringType)) } it should "instantiate the command with duplicated parameter names properly" in { - namespace1.findTask("test").get.command.instantiate(Map("x" -> WdlString("foo"))).get shouldEqual "./script foo foo foo" + task.instantiateCommand(Map("x" -> WdlString("foo"))).get shouldEqual "./script foo foo foo" } } diff --git a/src/test/scala/cromwell/binding/ScatterSpec.scala b/src/test/scala/cromwell/binding/ScatterSpec.scala new file mode 100644 index 00000000000..32ac48d2a94 --- /dev/null +++ b/src/test/scala/cromwell/binding/ScatterSpec.scala @@ -0,0 +1,70 @@ +package cromwell.binding + +import cromwell.parser.BackendType +import cromwell.util.SampleWdl +import org.scalatest.{FlatSpec, Matchers} + +class ScatterSpec extends FlatSpec with Matchers { + val namespace = NamespaceWithWorkflow.load(SampleWdl.ScatterWdl.wdlSource(), BackendType.LOCAL) + + it should "Have four 'children' objects" in { + namespace.workflow.children.size shouldEqual 4 + } + + it should "Have two 'direct Call descendents' objects" in { + Scope.collectCalls(namespace.workflow.children).size shouldEqual 2 + } + + it should "Have two 'direct Scatter descendents' objects" in { + Scope.collectScatters(namespace.workflow.children).size shouldEqual 2 + } + + it should "Have eight 'Call' objects" in { + namespace.workflow.calls.size shouldEqual 8 + } + + it should "Have four 'Scatter' objects" in { + namespace.workflow.scatters.size shouldEqual 4 + } + + it should "Have 'Scatter' objects indexed properly" in { + namespace.workflow.scatters(0).index shouldEqual 0 + namespace.workflow.scatters(1).index shouldEqual 3 + namespace.workflow.scatters(2).index shouldEqual 1 + namespace.workflow.scatters(3).index shouldEqual 2 + } + + it should "Not appear in Calls FQNs" in { + val calls: Seq[Call] = namespace.workflow.calls + calls.find(_.fullyQualifiedName == "w.A") shouldBe defined + calls.find(_.fullyQualifiedName == "w.B") shouldBe defined + calls.find(_.fullyQualifiedName == "w.C") shouldBe defined + calls.find(_.fullyQualifiedName == "w.E") shouldBe defined + calls.find(_.fullyQualifiedName == "w.G") shouldBe defined + calls.find(_.fullyQualifiedName == "w.H") shouldBe defined + calls.find(_.fullyQualifiedName == "w.F") shouldBe defined + calls.find(_.fullyQualifiedName == "w.D") shouldBe defined + } + + it should "Have correct FQNs for Scatter blocks" in { + namespace.workflow.scatters.find(_.fullyQualifiedNameWithIndexScopes == "w.$scatter_0") shouldBe defined + namespace.workflow.scatters.find(_.fullyQualifiedNameWithIndexScopes == "w.$scatter_0.$scatter_1") shouldBe defined + namespace.workflow.scatters.find(_.fullyQualifiedNameWithIndexScopes == "w.$scatter_0.$scatter_2") shouldBe defined + namespace.workflow.scatters.find(_.fullyQualifiedNameWithIndexScopes == "w.$scatter_3") shouldBe defined + } + + it should "Instantiate Scatters with correct item attributes" in { + namespace.workflow.scatters.find(_.name == "$scatter_0").get.item shouldEqual "item" + namespace.workflow.scatters.find(_.name == "$scatter_1").get.item shouldEqual "itemB" + namespace.workflow.scatters.find(_.name == "$scatter_2").get.item shouldEqual "itemB" + namespace.workflow.scatters.find(_.name == "$scatter_3").get.item shouldEqual "item" + } + + it should "Instantiate Scatters with correct collection attributes" in { + namespace.workflow.scatters.find(_.name == "$scatter_0").get.collection.toWdlString shouldEqual "A.A_out" + namespace.workflow.scatters.find(_.name == "$scatter_1").get.collection.toWdlString shouldEqual "B.B_out" + namespace.workflow.scatters.find(_.name == "$scatter_2").get.collection.toWdlString shouldEqual "B.B_out" + namespace.workflow.scatters.find(_.name == "$scatter_3").get.collection.toWdlString shouldEqual "A.A_out" + } + +} diff --git a/src/test/scala/cromwell/binding/ScopeSpec.scala b/src/test/scala/cromwell/binding/ScopeSpec.scala new file mode 100644 index 00000000000..2dd70ff0497 --- /dev/null +++ b/src/test/scala/cromwell/binding/ScopeSpec.scala @@ -0,0 +1,82 @@ +package cromwell.binding + +import cromwell.binding.AstTools.AstNodeName +import cromwell.parser.BackendType +import cromwell.parser.WdlParser.Ast +import cromwell.util.SampleWdl +import org.scalatest.{FlatSpec, Matchers} + +class ScopeSpec extends FlatSpec with Matchers { + + val namespace = NamespaceWithWorkflow.load(SampleWdl.ScatterWdl.wdlSource(), BackendType.LOCAL) + + it should "Have correct parent hierarchy" in { + val calls: Seq[Call] = namespace.workflow.calls + val scatters: Seq[Scatter] = namespace.workflow.scatters + val scatter0: Scatter = scatters.find(_.name == "$scatter_0").get + val scatter1: Scatter = scatters.find(_.name == "$scatter_1").get + val scatter2: Scatter = scatters.find(_.name == "$scatter_2").get + val scatter3: Scatter = scatters.find(_.name == "$scatter_3").get + + calls.find(_.fullyQualifiedName == "w.A").get.parent.get shouldEqual namespace.workflow + calls.find(_.fullyQualifiedName == "w.B").get.parent.get shouldEqual scatter0 + calls.find(_.fullyQualifiedName == "w.C").get.parent.get shouldEqual scatter0 + calls.find(_.fullyQualifiedName == "w.E").get.parent.get shouldEqual scatter0 + calls.find(_.fullyQualifiedName == "w.G").get.parent.get shouldEqual scatter1 + calls.find(_.fullyQualifiedName == "w.H").get.parent.get shouldEqual scatter2 + calls.find(_.fullyQualifiedName == "w.F").get.parent.get shouldEqual scatter3 + calls.find(_.fullyQualifiedName == "w.D").get.parent.get shouldEqual namespace.workflow + + scatter0.parent.get shouldEqual namespace.workflow + scatter1.parent.get shouldEqual scatter0 + scatter2.parent.get shouldEqual scatter0 + scatter3.parent.get shouldEqual namespace.workflow + + namespace.workflow.parent shouldEqual None + } + + it should "Have correct children hierarchy" in { + val calls: Seq[Call] = namespace.workflow.calls + val scatters: Seq[Scatter] = namespace.workflow.scatters + val scatter0: Scatter = scatters.find(_.name == "$scatter_0").get + val scatter1: Scatter = scatters.find(_.name == "$scatter_1").get + val scatter2: Scatter = scatters.find(_.name == "$scatter_2").get + val scatter3: Scatter = scatters.find(_.name == "$scatter_3").get + val callA: Call = calls.find(_.fullyQualifiedName == "w.A").get + val callB: Call = calls.find(_.fullyQualifiedName == "w.B").get + val callC: Call = calls.find(_.fullyQualifiedName == "w.C").get + val callD: Call = calls.find(_.fullyQualifiedName == "w.D").get + val callE: Call = calls.find(_.fullyQualifiedName == "w.E").get + val callF: Call = calls.find(_.fullyQualifiedName == "w.F").get + val callG: Call = calls.find(_.fullyQualifiedName == "w.G").get + val callH: Call = calls.find(_.fullyQualifiedName == "w.H").get + + namespace.workflow.children shouldEqual Seq(callA, scatter0, scatter3, callD) + + scatter0.children shouldEqual Seq(callB, callC, callE, scatter1, scatter2) + scatter1.children shouldEqual Seq(callG) + scatter2.children shouldEqual Seq(callH) + scatter3.children shouldEqual Seq(callF) + + callA.children shouldBe empty + callB.children shouldBe empty + callC.children shouldBe empty + callD.children shouldBe empty + callE.children shouldBe empty + callF.children shouldBe empty + callG.children shouldBe empty + callH.children shouldBe empty + } + + it should "throw an exception if trying to re-assign children on a scope" in { + the [UnsupportedOperationException] thrownBy { namespace.workflow.setChildren(Seq.empty) } should have message "children is write-once" + } + + it should "throw an exception if trying to generate a workflow from a non-workflow ast" in { + val callAst: Ast = AstTools.findAsts(namespace.ast, AstNodeName.Call).head + the [UnsupportedOperationException] thrownBy { + Scope.generateWorkflow(callAst, namespace.namespaces, namespace.tasks, namespace.wdlSyntaxErrorFormatter) + } should have message "Ast is not a 'Workflow Ast' but a 'Call Ast'" + } + +} diff --git a/src/test/scala/cromwell/binding/SyntaxErrorSpec.scala b/src/test/scala/cromwell/binding/SyntaxErrorSpec.scala index 89670619fef..290bbea3b97 100644 --- a/src/test/scala/cromwell/binding/SyntaxErrorSpec.scala +++ b/src/test/scala/cromwell/binding/SyntaxErrorSpec.scala @@ -18,8 +18,10 @@ class SyntaxErrorSpec extends FlatSpec with Matchers { val cgrepTaskWdl = """ |task cgrep { + | String pattern + | File in_file | command { - | grep '${pattern}' ${File in_file} | wc -l + | grep '${pattern}' ${in_file} | wc -l | } | output { | Int count = read_int(stdout()) @@ -54,8 +56,10 @@ class SyntaxErrorSpec extends FlatSpec with Matchers { | } |} |task cgrep { + | String pattern + | File in_file | command { - | grep '${pattern}' ${File in_file} | wc -l + | grep '${pattern}' ${in_file} | wc -l | } | output { | Int count = read_int(stdout()) @@ -80,8 +84,10 @@ class SyntaxErrorSpec extends FlatSpec with Matchers { | } |} |task cgrep { + | String pattern + | File in_file | command { - | grep '${pattern}' ${File in_file} | wc -l + | grep '${pattern}' ${in_file} | wc -l | } | output { | Int count = read_int(stdout()) @@ -105,8 +111,10 @@ class SyntaxErrorSpec extends FlatSpec with Matchers { | } |} |task cgrep { + | File in_file + | String pattern | command { - | grep '${pattern}' ${File in_file} | wc -l + | grep '${pattern}' ${in_file} | wc -l | } | output { | Int count = read_int(stdout()) @@ -170,22 +178,6 @@ class SyntaxErrorSpec extends FlatSpec with Matchers { |} |""".stripMargin) } - it should "detect incompatible types for same input" in { - expectError(""" - |task test { - | command { ./script ${String x} ${File x} ${x} } - |} - |workflow wf { call test } - """.stripMargin) - } - it should "detect when an input is defined differently at least once" in { - expectError(""" - |task test { - | command { ./script ${default="bar" String x?} ${String x} ${x} } - |} - |workflow wf { call test } - """.stripMargin) - } it should "detect unexpected EOF" in { expectError("workflow") } @@ -212,6 +204,8 @@ class SyntaxErrorSpec extends FlatSpec with Matchers { expectError( """ |task x { + | String a + | String b | command { ./script ${a} ${b} } |} | @@ -223,5 +217,18 @@ class SyntaxErrorSpec extends FlatSpec with Matchers { |} """.stripMargin) } + it should "detect when there are two workflows defined in a WDL file" in { + expectError( + """workflow w {} + |workflow x {} + """.stripMargin) + } + it should "detect when a Map does not have two parameterized types" in { + expectError( + """workflow w { + | Map[Int] i + |} + """.stripMargin) + } } diff --git a/src/test/scala/cromwell/binding/SyntaxHighlightSpec.scala b/src/test/scala/cromwell/binding/SyntaxHighlightSpec.scala new file mode 100644 index 00000000000..62738f110a6 --- /dev/null +++ b/src/test/scala/cromwell/binding/SyntaxHighlightSpec.scala @@ -0,0 +1,187 @@ +package cromwell.binding + +import cromwell.binding.formatter.{AnsiSyntaxHighlighter, HtmlSyntaxHighlighter, SyntaxFormatter} +import cromwell.parser.BackendType +import org.scalatest.{Matchers, WordSpecLike} + +class SyntaxHighlightSpec extends Matchers with WordSpecLike { + + "SyntaxFormatter for simple workflow" should { + val namespace = WdlNamespace.load( + """task t { + | String f + | Int p + | command { + | ./cmd ${f} ${p} + | } + |} + |workflow w { + | call t + | call t as u { + | input: f="abc", p=2 + | } + |} + """.stripMargin, BackendType.LOCAL + ) + + val console = + """\u001b[38;5;214mtask\u001b[0m \u001b[38;5;253mt\u001b[0m { + | \u001b[38;5;33mString\u001b[0m \u001b[38;5;112mf\u001b[0m + | \u001b[38;5;33mInt\u001b[0m \u001b[38;5;112mp\u001b[0m + | \u001b[38;5;214mcommand\u001b[0m { + | ./cmd ${f} ${p} + | } + |} + | + |\u001b[38;5;214mworkflow\u001b[0m \u001b[38;5;253mw\u001b[0m { + | \u001b[38;5;214mcall\u001b[0m \u001b[38;5;253mt\u001b[0m + | \u001b[38;5;214mcall\u001b[0m \u001b[38;5;253mt\u001b[0m as u { + | input: f="abc", p=2 + | } + |}""".stripMargin + + val html = + """task t { + | String f + | Int p + | command { + | ./cmd ${f} ${p} + | } + |} + | + |workflow w { + | call t + | call t as u { + | input: f="abc", p=2 + | } + |}""".stripMargin + + "format to console properly" in { + val actual = new SyntaxFormatter(AnsiSyntaxHighlighter).format(namespace) + actual shouldEqual console + } + + "format to HTML properly" in { + val actual = new SyntaxFormatter(HtmlSyntaxHighlighter).format(namespace) + actual shouldEqual html + } + } + + "SyntaxFormatter for more feature-rich workflow" should { + val namespace = WdlNamespace.load( + """import "foo.wdl" as foo_ns + | + |task t { + | String f + | Int p + | command { + | ./cmd ${f} ${p} + | } + |} + | + |task s { + | Array[File] input_file + | command <<< + | cat ${sep=' ' input_file} | awk '{s+=$1} END {print s}' + | >>> + | output { + | String s = read_string(stdout()) + | } + |} + | + |task r { + | command { python -c "import random; print(random.randint(1,100))" } + |} + | + |workflow w { + | Int p = 2+2 + | call t + | call t as u { + | input: f="abc", p=p + | } + |}""".stripMargin, + importResolver = (s:String) => "", + backendType = BackendType.LOCAL + ) + + val console = + """\u001b[38;5;214mimport\u001b[0m 'foo.wdl' as foo_ns + | + |\u001b[38;5;214mtask\u001b[0m \u001b[38;5;253mt\u001b[0m { + | \u001b[38;5;33mString\u001b[0m \u001b[38;5;112mf\u001b[0m + | \u001b[38;5;33mInt\u001b[0m \u001b[38;5;112mp\u001b[0m + | \u001b[38;5;214mcommand\u001b[0m { + | ./cmd ${f} ${p} + | } + |} + | + |\u001b[38;5;214mtask\u001b[0m \u001b[38;5;253ms\u001b[0m { + | \u001b[38;5;33mArray[File]\u001b[0m \u001b[38;5;112minput_file\u001b[0m + | \u001b[38;5;214mcommand\u001b[0m <<< + | cat ${sep=' ' input_file} | awk '{s+=$1} END {print s}' + | >>> + | \u001b[38;5;214moutput\u001b[0m { + | \u001b[38;5;33mString\u001b[0m \u001b[38;5;112ms\u001b[0m = \u001b[38;5;13mread_string\u001b[0m(\u001b[38;5;13mstdout\u001b[0m()) + | } + |} + | + |\u001b[38;5;214mtask\u001b[0m \u001b[38;5;253mr\u001b[0m { + | \u001b[38;5;214mcommand\u001b[0m { + | python -c "import random; print(random.randint(1,100))" + | } + |} + | + |\u001b[38;5;214mworkflow\u001b[0m \u001b[38;5;253mw\u001b[0m { + | \u001b[38;5;33mInt\u001b[0m \u001b[38;5;112mp\u001b[0m = 2 + 2 + | \u001b[38;5;214mcall\u001b[0m \u001b[38;5;253mt\u001b[0m + | \u001b[38;5;214mcall\u001b[0m \u001b[38;5;253mt\u001b[0m as u { + | input: f="abc", p=p + | } + |}""".stripMargin + + val html = + """import 'foo.wdl' as foo_ns + | + |task t { + | String f + | Int p + | command { + | ./cmd ${f} ${p} + | } + |} + | + |task s { + | Array[File] input_file + | command <<< + | cat ${sep=' ' input_file} | awk '{s+=$1} END {print s}' + | >>> + | output { + | String s = read_string(stdout()) + | } + |} + | + |task r { + | command { + | python -c "import random; print(random.randint(1,100))" + | } + |} + | + |workflow w { + | Int p = 2 + 2 + | call t + | call t as u { + | input: f="abc", p=p + | } + |}""".stripMargin + + "format to console properly" in { + val actual = new SyntaxFormatter(AnsiSyntaxHighlighter).format(namespace) + actual shouldEqual console + } + + "format to HTML properly" in { + val actual = new SyntaxFormatter(HtmlSyntaxHighlighter).format(namespace) + actual shouldEqual html + } + } +} diff --git a/src/test/scala/cromwell/binding/SyntaxHighlightTest.scala b/src/test/scala/cromwell/binding/SyntaxHighlightTest.scala deleted file mode 100644 index 936350f8aa7..00000000000 --- a/src/test/scala/cromwell/binding/SyntaxHighlightTest.scala +++ /dev/null @@ -1,54 +0,0 @@ -package cromwell.binding - -import cromwell.binding.formatter.{AnsiSyntaxHighlighter, HtmlSyntaxHighlighter, SyntaxFormatter} -import cromwell.parser.BackendType -import org.scalatest.{FlatSpec, Matchers} - -class SyntaxHighlightTest extends FlatSpec with Matchers { - val namespace = WdlNamespace.load( - s"""task t {command{./cmd $${f} $${Int p}}} - |workflow w { - | call t - | call t as u { - | input: f="abc", p=2 - | } - |} - """.stripMargin, BackendType.LOCAL - ) - - "SyntaxFormatter" should "produce tagged HTML" in { - val formatter = new SyntaxFormatter(HtmlSyntaxHighlighter) - val actual = formatter.format(namespace) - val expected = s"""task t { - | command { - | ./cmd $${String f} $${Int p} - | } - |} - | - |workflow w { - | call t - | call t as u { - | input: f="abc", p=2 - | } - |}""".stripMargin - actual shouldEqual expected - } - - it should "produce ANSI terminal output" in { - val formatter = new SyntaxFormatter(AnsiSyntaxHighlighter) - val actual = formatter.format(namespace) - val expected = s"""\u001b[38;5;214mtask\u001b[0m \u001b[38;5;253mt\u001b[0m { - | command { - | ./cmd $${\u001b[38;5;33mString\u001b[0m \u001b[38;5;112mf\u001b[0m} $${\u001b[38;5;33mInt\u001b[0m \u001b[38;5;112mp\u001b[0m} - | } - |} - | - |\u001b[38;5;214mworkflow\u001b[0m \u001b[38;5;253mw\u001b[0m { - | \u001b[38;5;214mcall\u001b[0m \u001b[38;5;253mt\u001b[0m - | \u001b[38;5;214mcall\u001b[0m \u001b[38;5;253mt\u001b[0m as u { - | input: f="abc", p=2 - | } - |}""".stripMargin - actual shouldEqual expected - } -} diff --git a/src/test/scala/cromwell/binding/ThreeStepImportNamespaceAliasSpec.scala b/src/test/scala/cromwell/binding/ThreeStepImportNamespaceAliasSpec.scala index 19a48dd95ea..3f9d3598f28 100644 --- a/src/test/scala/cromwell/binding/ThreeStepImportNamespaceAliasSpec.scala +++ b/src/test/scala/cromwell/binding/ThreeStepImportNamespaceAliasSpec.scala @@ -16,8 +16,10 @@ class ThreeStepImportNamespaceAliasSpec extends FlatSpec with Matchers { val cgrepTaskWdl = """ |task cgrep { + | String pattern + | File in_file | command { - | grep '${pattern}' ${File in_file} | wc -l + | grep '${pattern}' ${in_file} | wc -l | } | output { | Int count = read_int(stdout()) @@ -26,8 +28,9 @@ class ThreeStepImportNamespaceAliasSpec extends FlatSpec with Matchers { val wcTaskWdl = """ |task wc { + | File in_file | command { - | cat ${File in_file} | wc -l + | cat ${in_file} | wc -l | } | output { | Int count = read_int(stdout()) diff --git a/src/test/scala/cromwell/binding/ThreeStepImportNamespaceSpec.scala b/src/test/scala/cromwell/binding/ThreeStepImportNamespaceSpec.scala index acc3ebed969..6e983af2038 100644 --- a/src/test/scala/cromwell/binding/ThreeStepImportNamespaceSpec.scala +++ b/src/test/scala/cromwell/binding/ThreeStepImportNamespaceSpec.scala @@ -16,8 +16,10 @@ class ThreeStepImportNamespaceSpec extends FlatSpec with Matchers { val cgrepTaskWdl = """ |task cgrep { + | String pattern + | String in_file | command { - | grep '${pattern}' ${File in_file} | wc -l + | grep '${pattern}' ${in_file} | wc -l | } | output { | Int count = read_int(stdout()) @@ -26,8 +28,9 @@ class ThreeStepImportNamespaceSpec extends FlatSpec with Matchers { val wcTaskWdl = """ |task wc { + | File in_file | command { - | cat ${File in_file} | wc -l + | cat ${in_file} | wc -l | } | output { | Int count = read_int(stdout()) diff --git a/src/test/scala/cromwell/binding/ThreeStepImportSpec.scala b/src/test/scala/cromwell/binding/ThreeStepImportSpec.scala index 21395c1d35f..5b742395c05 100644 --- a/src/test/scala/cromwell/binding/ThreeStepImportSpec.scala +++ b/src/test/scala/cromwell/binding/ThreeStepImportSpec.scala @@ -16,8 +16,10 @@ class ThreeStepImportSpec extends FlatSpec with Matchers { val cgrepTaskWdl = """ |task cgrep { + | String pattern + | File in_file | command { - | grep '${pattern}' ${File in_file} | wc -l + | grep '${pattern}' ${in_file} | wc -l | } | output { | Int count = read_int(stdout()) @@ -26,8 +28,9 @@ class ThreeStepImportSpec extends FlatSpec with Matchers { val wcTaskWdl = """ |task wc { + | File in_file | command { - | cat ${File in_file} | wc -l + | cat ${in_file} | wc -l | } | output { | Int count = read_int(stdout()) diff --git a/src/test/scala/cromwell/binding/ThreeStepSpec.scala b/src/test/scala/cromwell/binding/ThreeStepSpec.scala index 6e89edb03b3..3308653fea2 100644 --- a/src/test/scala/cromwell/binding/ThreeStepSpec.scala +++ b/src/test/scala/cromwell/binding/ThreeStepSpec.scala @@ -33,7 +33,7 @@ class ThreeStepSpec extends FlatSpec with Matchers { val task = namespace.findTask("wc") getOrElse fail("No 'wc' task found") task.name shouldEqual "wc" task.inputs shouldEqual Vector(TaskInput("in_file", WdlFileType, postfixQuantifier=None)) - task.command.instantiate(Map("in_file" -> WdlFile("/path/to/file"))).get shouldEqual "cat /path/to/file | wc -l" + task.instantiateCommand(Map("in_file" -> WdlFile("/path/to/file"))).get shouldEqual "cat /path/to/file | wc -l" task.outputs.size shouldEqual 1 task.outputs.head.name shouldEqual "count" task.outputs.head.wdlType shouldEqual WdlIntegerType @@ -45,7 +45,7 @@ class ThreeStepSpec extends FlatSpec with Matchers { TaskInput("pattern", WdlStringType, postfixQuantifier=None), TaskInput("in_file", WdlFileType, postfixQuantifier=None) ) - task.command.instantiate( + task.instantiateCommand( Map("pattern" -> WdlString("^...$"), "in_file" -> WdlFile("/path/to/file")) ).get shouldEqual "grep '^...$' /path/to/file | wc -l" task.outputs.size shouldEqual 1 @@ -56,7 +56,7 @@ class ThreeStepSpec extends FlatSpec with Matchers { val task = namespace.findTask("ps") getOrElse fail("No 'ps' task found") task.name shouldEqual "ps" task.inputs shouldEqual Vector() - task.command.instantiate(Map()).get shouldEqual "ps" + task.instantiateCommand(Map()).get shouldEqual "ps" task.outputs.size shouldEqual 1 task.outputs.head.name shouldEqual "procs" task.outputs.head.wdlType shouldEqual WdlFileType diff --git a/src/test/scala/cromwell/binding/WdlExpressionSpec.scala b/src/test/scala/cromwell/binding/WdlExpressionSpec.scala index dbcd524eb74..8cc828f7cc5 100644 --- a/src/test/scala/cromwell/binding/WdlExpressionSpec.scala +++ b/src/test/scala/cromwell/binding/WdlExpressionSpec.scala @@ -11,9 +11,6 @@ class WdlExpressionSpec extends FlatSpec with Matchers { val expr: String => WdlExpression = WdlExpression.fromString def noLookup(String: String): WdlValue = fail("No identifiers should be looked up in this test") - class NoFunctions extends WdlFunctions { - def getFunction(name: String): WdlFunction = fail("No functions should be called in this test") - } def identifierLookup(String: String): WdlValue = { String match { diff --git a/src/test/scala/cromwell/binding/WdlExpressionToFileSpec.scala b/src/test/scala/cromwell/binding/WdlExpressionToFileSpec.scala index 3ec6b500f6d..a6150d4e08f 100644 --- a/src/test/scala/cromwell/binding/WdlExpressionToFileSpec.scala +++ b/src/test/scala/cromwell/binding/WdlExpressionToFileSpec.scala @@ -1,7 +1,7 @@ package cromwell.binding import cromwell.binding.values._ -import cromwell.engine.EngineFunctions +import org.scalatest.exceptions.TestFailedException import org.scalatest.mock.MockitoSugar import org.scalatest.{Matchers, FlatSpec} import scala.language.postfixOps @@ -40,10 +40,9 @@ class WdlExpressionToFileSpec extends FlatSpec with Matchers with MockitoSugar { "anonFiles function" should "identify read_int's argument as a files" in { val e: WdlExpression = expr("""read_int("myfile.txt")""") e.preevaluateExpressionForFilenames(noLookup, engineFunctions) match { - case Success(files) => { + case Success(files) => assert(files.size == 1) assert(files.head == WdlFile("myfile.txt")) - } case Failure(error) => fail(error) } } @@ -51,22 +50,24 @@ class WdlExpressionToFileSpec extends FlatSpec with Matchers with MockitoSugar { "anonFiles function" should "evaluate expressions within read_int's ( and ) as a single file" in { val e: WdlExpression = expr("""read_int("/bin/bash/" + "myfile.txt")""") e.preevaluateExpressionForFilenames(noLookup, engineFunctions) match { - case Success(files) => { + case Success(files) => assert(files.size == 1) assert(files.head == WdlFile("/bin/bash/myfile.txt")) - } case Failure(error) => fail(error) } } - // I can't see any use for this particular combination but it's possible and should work, so let's test it: - "anonFiles function" should "evaluate expressions within read_int's which include pre-evaluable function calls" in { + "anonFiles function" should "not allow read_ints containing function calls within other expressions" in { val e: WdlExpression = expr("""read_int(stdout() + "3")""") e.preevaluateExpressionForFilenames(noLookup, engineFunctions) match { - case Success(files) => { - assert(files.size == 1) - assert(files.head == WdlFile("job.stdout.txt/3")) - } + case Success(files) => fail("Functions shouldn't be allowed in complex expressions.") + case Failure(error) => // good + } + } + "anonFiles function" should "not identify stdout as an anonymous output" in { + val e: WdlExpression = expr("""read_int(stdout())""") + e.preevaluateExpressionForFilenames(noLookup, engineFunctions) match { + case Success(files) => assert(files isEmpty) case Failure(error) => fail(error) } } @@ -82,10 +83,9 @@ class WdlExpressionToFileSpec extends FlatSpec with Matchers with MockitoSugar { "anonFiles function" should "find file names modified by unary operators" in { val e: WdlExpression = expr(""" -read_int("/etc/file1")""") e.preevaluateExpressionForFilenames(noLookup, engineFunctions) match { - case Success(files) => { + case Success(files) => assert(files.size == 1) assert(files exists {_.value == "/etc/file1"}) - } case Failure(error) => fail(error) } } @@ -93,11 +93,10 @@ class WdlExpressionToFileSpec extends FlatSpec with Matchers with MockitoSugar { "anonFiles function" should "find two file names for two consecutive read_X functions" in { val e: WdlExpression = expr("""read_int("/etc/file1") + read_string("/bin/file2")""") e.preevaluateExpressionForFilenames(noLookup, engineFunctions) match { - case Success(files) => { + case Success(files) => assert(files.size == 2) assert(files exists {_.value == "/etc/file1"}) assert(files exists {_.value == "/bin/file2"}) - } case Failure(error) => fail(error) } } @@ -105,32 +104,28 @@ class WdlExpressionToFileSpec extends FlatSpec with Matchers with MockitoSugar { "anonFiles function" should "find all file names in arbitrarily long sequences of read_X functions" in { val e: WdlExpression = expr("""read_int("/etc/file1") + read_string("/bin/file2") + read_string("/bin/file3") + read_string("/bin/file4") + read_string("/bin/file5")""") e.preevaluateExpressionForFilenames(noLookup, engineFunctions) match { - case Success(files) => { + case Success(files) => assert(files.size == 5) assert(files exists {_.value == "/etc/file1"}) assert(files exists {_.value == "/bin/file2"}) assert(files exists {_.value == "/bin/file3"}) assert(files exists {_.value == "/bin/file4"}) assert(files exists {_.value == "/bin/file5"}) - } case Failure(error) => fail(error) } } } -class MockEngineFunctions extends EngineFunctions { +class MockEngineFunctions extends WdlStandardLibraryFunctions { // It's important to ensure that these are never called during pre-evaluation: override protected def read_int(params: Seq[Try[WdlValue]]): Try[WdlInteger] = { - assert(false, "The active 'read_int' function should not be used during pre-evaluation") - ??? + throw new TestFailedException("The active 'read_int' function should not be used during pre-evaluation", 0) } override protected def read_string(params: Seq[Try[WdlValue]]): Try[WdlString] = { - assert(false, "The active 'read_string' function should not be used during pre-evaluation") - ??? + throw new TestFailedException("The active 'read_string' function should not be used during pre-evaluation", 0) } override protected def read_lines(params: Seq[Try[WdlValue]]): Try[WdlArray] = { - assert(false, "The active 'read_lines' function should not be used during pre-evaluation") - ??? + throw new TestFailedException("The active 'read_lines' function should not be used during pre-evaluation", 0) } // These pre-evaluable functions can be called during the pre-evaluation. diff --git a/src/test/scala/cromwell/binding/WdlTypeSpec.scala b/src/test/scala/cromwell/binding/WdlTypeSpec.scala deleted file mode 100644 index 700bbb0c4cb..00000000000 --- a/src/test/scala/cromwell/binding/WdlTypeSpec.scala +++ /dev/null @@ -1,56 +0,0 @@ -package cromwell.binding - -import java.nio.file.Paths - -import cromwell.binding.types._ -import cromwell.binding.values._ -import org.scalatest.{FlatSpec, Matchers} - -class WdlTypeSpec extends FlatSpec with Matchers { - "WdlType class" should "stringify WdlBoolean to 'Boolean'" in { - WdlBooleanType.toWdlString shouldEqual "Boolean" - } - it should "stringify WdlInteger to 'Integer'" in { - WdlIntegerType.toWdlString shouldEqual "Int" - } - it should "stringify WdlFloat to 'Float'" in { - WdlFloatType.toWdlString shouldEqual "Float" - } - it should "stringify WdlObject to 'Object'" in { - WdlObjectType.toWdlString shouldEqual "Object" - } - it should "stringify WdlString to 'String'" in { - WdlStringType.toWdlString shouldEqual "String" - } - it should "stringify WdlFile to 'File'" in { - WdlFileType.toWdlString shouldEqual "File" - } - - "WdlBoolean" should "support expected coercions" in { - WdlBooleanType.coerceRawValue("true").get shouldEqual WdlBoolean.True - WdlBooleanType.coerceRawValue("FALSE").get shouldEqual WdlBoolean.False - WdlBooleanType.coerceRawValue(false).get shouldEqual WdlBoolean.False - - WdlBooleanType.coerceRawValue("I like turtles").isFailure shouldBe true - } - - "WdlString" should "support expected coercions" in { - WdlStringType.coerceRawValue("foo").get shouldEqual WdlString("foo") - WdlStringType.coerceRawValue(-1).isFailure shouldBe true - } - - "WdlFile" should "support expected coercions" in { - WdlFileType.coerceRawValue("/etc/passwd").get shouldEqual WdlFile("/etc/passwd") - WdlFileType.coerceRawValue(-1).isFailure shouldBe true - } - - "WdlInteger" should "support expected coercions" in { - WdlIntegerType.coerceRawValue(42).get shouldEqual WdlInteger(42) - WdlIntegerType.coerceRawValue("FAIL").isFailure shouldBe true - } - - "WdlFloatType" should "support expected coercions" in { - WdlFloatType.coerceRawValue(33.3).get shouldEqual WdlFloat(33.3) - WdlFloatType.coerceRawValue("FAIL").isFailure shouldBe true - } -} diff --git a/src/test/scala/cromwell/binding/types/WdlMapTypeSpec.scala b/src/test/scala/cromwell/binding/types/WdlMapTypeSpec.scala new file mode 100644 index 00000000000..9ed89b985e0 --- /dev/null +++ b/src/test/scala/cromwell/binding/types/WdlMapTypeSpec.scala @@ -0,0 +1,85 @@ +package cromwell.binding.types + +import cromwell.binding.values.{WdlMap, WdlInteger, WdlString} +import cromwell.parser.WdlParser.SyntaxError +import org.scalatest.{FlatSpec, Matchers} +import spray.json.{JsObject, JsArray, JsNumber} + +import scala.util.{Failure, Success} + +class WdlMapTypeSpec extends FlatSpec with Matchers { + val stringIntMap = WdlMap(WdlMapType(WdlStringType, WdlIntegerType), Map( + WdlString("a") -> WdlInteger(1), + WdlString("b") -> WdlInteger(2), + WdlString("c") -> WdlInteger(3) + )) + "WdlMap" should "stringify its value" in { + stringIntMap.toWdlString shouldEqual "{\"a\": 1, \"b\": 2, \"c\": 3}" + } + "WdlMapType" should "coerce Map(\"a\":1, \"b\":2, \"c\": 3) into a WdlMap" in { + WdlMapType(WdlStringType, WdlIntegerType).coerceRawValue(Map("a" -> 1, "b" -> 2, "c" -> 3)) match { + case Success(array) => array shouldEqual stringIntMap + case Failure(f) => fail(s"exception while coercing map: $f") + } + } + it should "coerce a JsObject into a WdlMap" in { + WdlMapType(WdlStringType, WdlIntegerType).coerceRawValue(JsObject(Map("a" -> JsNumber(1), "b" -> JsNumber(2), "c" -> JsNumber(3)))) match { + case Success(array) => array shouldEqual stringIntMap + case Failure(f) => fail(s"exception while coercing JsObject: $f") + } + } + it should "stringify its type" in { + stringIntMap.wdlType.toWdlString shouldEqual "Map[String, Int]" + } + it should "convert WDL source code to WdlMap" in { + WdlMapType(WdlStringType, WdlIntegerType).fromWdlString("{\"a\": 1, \"b\": 2, \"c\": 3}") shouldEqual stringIntMap + } + it should "NOT successfully convert WDL source code to WdlMap if passed a bogus AST" in { + try { + WdlMapType(WdlStringType, WdlIntegerType).fromWdlString("workflow wf{}") + fail("should not have succeeded") + } catch { + case _: SyntaxError => // expected + } + } + it should "NOT successfully convert WDL source code to WdlMap if passed a bogus AST (2)" in { + try { + WdlMapType(WdlStringType, WdlIntegerType).fromWdlString("100") + fail("should not have succeeded") + } catch { + case _: SyntaxError => // expected + } + } + it should "NOT successfully convert WDL source code to WdlMap if passed a bogus AST (3)" in { + try { + WdlMapType(WdlStringType, WdlIntegerType).fromWdlString("{1:x(),2:stdout()}") + fail("should not have succeeded") + } catch { + case _: SyntaxError => // expected + } + } + it should "NOT successfully convert WDL source code to WdlMap if passed a bogus AST (4)" in { + try { + WdlMapType(WdlStringType, WdlIntegerType).fromWdlString("{1:var,2:var}") + fail("should not have succeeded") + } catch { + case _: SyntaxError => // expected + } + } + it should "detect invalid map construction if there are mixed types" in { + try { + WdlMap(WdlMapType(WdlStringType, WdlStringType), Map(WdlInteger(0) -> WdlString("foo"), WdlString("x") -> WdlInteger(2))) + fail("Map initialization should have failed") + } catch { + case _: UnsupportedOperationException => // expected + } + } + it should "detect invalid map construction if type does not match the input map type" in { + try { + WdlMap(WdlMapType(WdlStringType, WdlStringType), Map(WdlInteger(2) -> WdlInteger(3))) + fail("Invalid map initialization should have failed") + } catch { + case _: UnsupportedOperationException => // expected + } + } +} diff --git a/src/test/scala/cromwell/binding/types/WdlTypeSpec.scala b/src/test/scala/cromwell/binding/types/WdlTypeSpec.scala index 3109e580855..19d8b946a09 100644 --- a/src/test/scala/cromwell/binding/types/WdlTypeSpec.scala +++ b/src/test/scala/cromwell/binding/types/WdlTypeSpec.scala @@ -1,12 +1,64 @@ package cromwell.binding.types +import cromwell.binding.types._ +import cromwell.binding.values._ import cromwell.parser.WdlParser.SyntaxError import org.scalatest.prop.TableDrivenPropertyChecks._ import org.scalatest.prop.Tables.Table -import org.scalatest.{Matchers, FlatSpec} +import org.scalatest.{FlatSpec, Matchers} +import spray.json.JsString class WdlTypeSpec extends FlatSpec with Matchers { - behavior of "WdlValue" + "WdlType class" should "stringify WdlBoolean to 'Boolean'" in { + WdlBooleanType.toWdlString shouldEqual "Boolean" + } + it should "stringify WdlInteger to 'Integer'" in { + WdlIntegerType.toWdlString shouldEqual "Int" + } + it should "stringify WdlFloat to 'Float'" in { + WdlFloatType.toWdlString shouldEqual "Float" + } + it should "stringify WdlObject to 'Object'" in { + WdlObjectType.toWdlString shouldEqual "Object" + } + it should "stringify WdlString to 'String'" in { + WdlStringType.toWdlString shouldEqual "String" + } + it should "stringify WdlFile to 'File'" in { + WdlFileType.toWdlString shouldEqual "File" + } + + "WdlBoolean" should "support expected coercions" in { + WdlBooleanType.coerceRawValue("true").get shouldEqual WdlBoolean.True + WdlBooleanType.coerceRawValue("FALSE").get shouldEqual WdlBoolean.False + WdlBooleanType.coerceRawValue(false).get shouldEqual WdlBoolean.False + + WdlBooleanType.coerceRawValue("I like turtles").isFailure shouldBe true + } + + "WdlString" should "support expected coercions" in { + WdlStringType.coerceRawValue("foo").get shouldEqual WdlString("foo") + WdlStringType.coerceRawValue(-1).isFailure shouldBe true + } + + "WdlFile" should "support expected coercions" in { + WdlFileType.coerceRawValue("/etc/passwd").get shouldEqual WdlFile("/etc/passwd") + WdlFileType.coerceRawValue(-1).isFailure shouldBe true + } + + "WdlInteger" should "support expected coercions" in { + WdlIntegerType.coerceRawValue(42).get shouldEqual WdlInteger(42) + WdlIntegerType.coerceRawValue("42").get shouldEqual WdlInteger(42) + WdlIntegerType.coerceRawValue(JsString("42")).get shouldEqual WdlInteger(42) + WdlIntegerType.coerceRawValue("FAIL").isFailure shouldBe true + } + + "WdlFloatType" should "support expected coercions" in { + WdlFloatType.coerceRawValue(33.3).get shouldEqual WdlFloat(33.3) + WdlFloatType.coerceRawValue("33.3").get shouldEqual WdlFloat(33.3) + WdlFloatType.coerceRawValue(JsString("33.3")).get shouldEqual WdlFloat(33.3) + WdlFloatType.coerceRawValue("FAIL").isFailure shouldBe true + } val wdlValueRawStrings = Table( ("WdlSource", "WdlType"), diff --git a/src/test/scala/cromwell/engine/EngineFunctionsSpec.scala b/src/test/scala/cromwell/engine/EngineFunctionsSpec.scala new file mode 100644 index 00000000000..0292310c1d8 --- /dev/null +++ b/src/test/scala/cromwell/engine/EngineFunctionsSpec.scala @@ -0,0 +1,26 @@ +package cromwell.engine + +import cromwell.binding.NoFunctions + +import cromwell.binding.values.WdlValue +import org.scalatest.{FlatSpec, Matchers} + +import scala.util.{Failure, Success, Try} + +class EngineFunctionsSpec extends FlatSpec with Matchers { + def expectFailure(value: Try[WdlValue]) = value match { + case Success(s) => fail(s"$s: Expected this function invocation to fail") + case Failure(ex) => // expected + } + "EngineFunctions" should "all initially be undefined" in { + val noFunctions = new NoFunctions + val stdFunctions = Seq( + "stdout", "stderr", "read_lines", "read_tsv", "read_map", "read_object", "read_objects", + "read_json", "read_int", "read_string", "read_float", "read_boolean", "write_lines", + "write_tsv", "write_map", "write_object", "write_objects", "write_json" + ) + stdFunctions.foreach {func => + expectFailure(noFunctions.getFunction(func)(Seq.empty[Try[WdlValue]])) + } + } +} diff --git a/src/test/scala/cromwell/engine/WorkflowAbortSpec.scala b/src/test/scala/cromwell/engine/WorkflowAbortSpec.scala new file mode 100644 index 00000000000..93a35092856 --- /dev/null +++ b/src/test/scala/cromwell/engine/WorkflowAbortSpec.scala @@ -0,0 +1,59 @@ +package cromwell.engine + +import akka.testkit.TestActorRef +import cromwell.{CromwellTestkitSpec, binding, CromwellSpec} +import cromwell.engine.db.DataAccess._ +import cromwell.engine.workflow.{WorkflowActor, WorkflowManagerActor} +import cromwell.engine.workflow.WorkflowManagerActor._ +import cromwell.util.SampleWdl.{TripleSleep, HelloWorld} + +class WorkflowAbortSpec extends CromwellTestkitSpec("WorkflowAbortSpec") { + + // TODO: When re-enabled, this test also needs to check that child processes have actually been stopped. + "A WorkflowManagerActor" should { + +// "abort the triple-wait workflow" in { +// withDataAccess { dataAccess => +// implicit val workflowManagerActor = TestActorRef(WorkflowManagerActor.props(dataAccess, CromwellSpec.BackendInstance), self, "Test the WorkflowManagerActor") +// +// val waitThreshold = 10 +// +// // Start the workflow: +// val workflowId = messageAndWait[WorkflowId](SubmitWorkflow(TripleSleep.wdlSource(), TripleSleep.wdlJson, TripleSleep.rawInputs)) +// +// def waitForStarted(currentAttempt: Int): Unit = { +// val status = messageAndWait[Option[WorkflowState]](WorkflowStatus(workflowId)) +// status match { +// case None | Some(WorkflowSubmitted) => +// if (currentAttempt > waitThreshold) { fail("Workflow took too long to start") } +// Thread.sleep(1000) +// waitForStarted(currentAttempt + 1) +// case Some(_) => // We're good to continue +// } +// } +// +// def waitForAborted(currentAttempt: Int): Unit = { +// val status = messageAndWait[Option[WorkflowState]](WorkflowStatus(workflowId)) +// status match { +// case Some(WorkflowAborted) => // All good +// case Some(x: WorkflowState) if x.isTerminal => fail("Unexpected end state of workflow: " + x) +// case Some(_) => +// if (currentAttempt > waitThreshold) { fail("Workflow took too long to complete after an abort attempt") } +// Thread.sleep(1000) +// waitForAborted(currentAttempt + 1) +// case None => fail("Workflow mysteriously disappeared") +// } +// } +// +// // Wait for the workflow to start: +// waitForStarted(0) +// +// // Abort the workflow: +// workflowManagerActor ! WorkflowAbort(workflowId) +// +// // Wait for the workflow to complete: +// waitForAborted(0) +// } +// } + } +} diff --git a/src/test/scala/cromwell/engine/WorkflowManagerActorSpec.scala b/src/test/scala/cromwell/engine/WorkflowManagerActorSpec.scala index 45b7e308821..5b037cfd57a 100644 --- a/src/test/scala/cromwell/engine/WorkflowManagerActorSpec.scala +++ b/src/test/scala/cromwell/engine/WorkflowManagerActorSpec.scala @@ -4,7 +4,7 @@ import java.util.UUID import akka.testkit.TestActorRef import cromwell.binding._ -import cromwell.binding.command.Command +import cromwell.binding.command.CommandPart import cromwell.binding.types.WdlStringType import cromwell.binding.values.WdlString import cromwell.engine.ExecutionStatus.{NotStarted, Running} @@ -12,9 +12,7 @@ import cromwell.engine.backend.StdoutStderr import cromwell.engine.backend.local.LocalBackend import cromwell.engine.db.DataAccess.{WorkflowInfo, _} import cromwell.engine.workflow.WorkflowManagerActor -import cromwell.engine.workflow.WorkflowManagerActor.CallOutputs -import cromwell.engine.workflow.WorkflowManagerActor.WorkflowOutputs -import cromwell.engine.workflow.WorkflowManagerActor._ +import cromwell.engine.workflow.WorkflowManagerActor.{CallOutputs, WorkflowOutputs, _} import cromwell.parser.BackendType import cromwell.util.SampleWdl import cromwell.util.SampleWdl.{HelloWorld, HelloWorldWithoutWorkflow, Incr} @@ -25,7 +23,6 @@ import scala.concurrent.{Await, ExecutionContext, Future} import scala.language.postfixOps import scala.util.{Failure, Success, Try} - class WorkflowManagerActorSpec extends CromwellTestkitSpec("WorkflowManagerActorSpec") { "A WorkflowManagerActor" should { @@ -62,8 +59,8 @@ class WorkflowManagerActorSpec extends CromwellTestkitSpec("WorkflowManagerActor "Try to restart workflows when there are workflows in restartable states" in { val workflows = Map( - UUID.randomUUID() -> WorkflowSubmitted, - UUID.randomUUID() -> WorkflowRunning) + WorkflowId(UUID.randomUUID()) -> WorkflowSubmitted, + WorkflowId(UUID.randomUUID()) -> WorkflowRunning) val ids = workflows.keys.map(_.toString).toSeq.sorted val key = SymbolStoreKey("hello.hello", "addressee", None, input = true) val symbols = Map(key -> new SymbolStoreEntry(key, WdlStringType, Option(WdlString("world")))) @@ -77,8 +74,8 @@ class WorkflowManagerActorSpec extends CromwellTestkitSpec("WorkflowManagerActor val status = if (workflowState == WorkflowSubmitted) NotStarted else Running val workflowInfo = new WorkflowInfo(workflowId, wdlSource, wdlInputs) // FIXME? null AST - val task = new Task("taskName", Seq.empty[Declaration], new Command(Seq.empty), Seq.empty, null, BackendType.LOCAL) - val call = new Call(None, key.scope, task, Map.empty) + val task = new Task("taskName", Seq.empty[Declaration], Seq.empty[CommandPart], Seq.empty, null, BackendType.LOCAL) + val call = new Call(None, key.scope, task, Map.empty, None) for { _ <- dataAccess.createWorkflow(workflowInfo, symbols.values, Seq(call), new LocalBackend()) _ <- dataAccess.updateWorkflowState(workflowId, workflowState) @@ -139,7 +136,7 @@ class WorkflowManagerActorSpec extends CromwellTestkitSpec("WorkflowManagerActor within(TestExecutionTimeout) { implicit val workflowManagerActor = TestActorRef(WorkflowManagerActor.props(dataAccess, CromwellSpec.BackendInstance), self, "Test WorkflowManagerActor output lookup failure") - val id = UUID.randomUUID() + val id = WorkflowId(UUID.randomUUID()) Try { messageAndWait[binding.WorkflowOutputs](WorkflowOutputs(id)) } match { @@ -155,7 +152,7 @@ class WorkflowManagerActorSpec extends CromwellTestkitSpec("WorkflowManagerActor within(TestExecutionTimeout) { implicit val workflowManagerActor = TestActorRef(WorkflowManagerActor.props(dataAccess, CromwellSpec.BackendInstance), self, "Test WorkflowManagerActor call log lookup failure") - val id = UUID.randomUUID() + val id = WorkflowId.randomId() Try { messageAndWait[StdoutStderr](CallStdoutStderr(id, "foo.bar")) } match { @@ -171,7 +168,7 @@ class WorkflowManagerActorSpec extends CromwellTestkitSpec("WorkflowManagerActor within(TestExecutionTimeout) { implicit val workflowManagerActor = TestActorRef(WorkflowManagerActor.props(dataAccess, CromwellSpec.BackendInstance), self, "Test WorkflowManagerActor log lookup failure") - val id = UUID.randomUUID() + val id = WorkflowId.randomId() Try { messageAndWait[Map[LocallyQualifiedName, StdoutStderr]](WorkflowStdoutStderr(id)) } match { diff --git a/src/test/scala/cromwell/engine/backend/local/LocalBackendSpec.scala b/src/test/scala/cromwell/engine/backend/local/LocalBackendSpec.scala index a747d4ba105..9406ac90121 100644 --- a/src/test/scala/cromwell/engine/backend/local/LocalBackendSpec.scala +++ b/src/test/scala/cromwell/engine/backend/local/LocalBackendSpec.scala @@ -8,6 +8,7 @@ import cromwell.binding.WdlExpression.ScopedLookupFunction import cromwell.binding.values.WdlFile import cromwell.binding.{Call, Task, WorkflowDescriptor} import cromwell.engine.backend.Backend.StdoutStderrException +import cromwell.engine.{AbortFunctionRegistration, WorkflowId} import org.mockito.Mockito._ import org.scalatest.mock.MockitoSugar import org.scalatest.{FlatSpec, Matchers} @@ -24,7 +25,7 @@ class LocalBackendSpec extends FlatSpec with Matchers with MockitoSugar { // Mock setup: val mockWorkflowDescriptor: WorkflowDescriptor = mock[WorkflowDescriptor] when(mockWorkflowDescriptor.name) thenReturn "Mocky" - when(mockWorkflowDescriptor.id) thenReturn UUID.randomUUID + when(mockWorkflowDescriptor.id) thenReturn WorkflowId(UUID.randomUUID) val mockScopedLookupFunction: ScopedLookupFunction = mock[ScopedLookupFunction] def testFailOnStderr(failOnStderr: Boolean, command: String, expectSuccess: Boolean): Unit = { @@ -34,7 +35,7 @@ class LocalBackendSpec extends FlatSpec with Matchers with MockitoSugar { when(call.failOnStderr) thenReturn failOnStderr when(call.task) thenReturn task when(task.outputs) thenReturn Seq() - new LocalBackend().executeCommand(command, mockWorkflowDescriptor, call, call.inputMappings, mockScopedLookupFunction) match { + new LocalBackend().executeCommand(command, mockWorkflowDescriptor, call, call.inputMappings, mockScopedLookupFunction, AbortFunctionRegistration(_ => ())) match { case Failure(e) => if (expectSuccess) fail("A call in a failOnStderr test which should have succeeded has failed ", e) case Success(_) => if (!expectSuccess) fail("A call in a failOnStderr test which should have failed has succeeded") } diff --git a/src/test/scala/cromwell/engine/db/slick/SlickDataAccessSpec.scala b/src/test/scala/cromwell/engine/db/slick/SlickDataAccessSpec.scala index c6178195346..2bc5b4fb801 100644 --- a/src/test/scala/cromwell/engine/db/slick/SlickDataAccessSpec.scala +++ b/src/test/scala/cromwell/engine/db/slick/SlickDataAccessSpec.scala @@ -5,13 +5,13 @@ import java.util.UUID import cromwell.binding.WdlExpression.ScopedLookupFunction import cromwell.binding._ -import cromwell.binding.command.Command +import cromwell.binding.command.CommandPart import cromwell.binding.types.{WdlArrayType, WdlStringType} -import cromwell.binding.values.{WdlFile, WdlArray, WdlString} +import cromwell.binding.values.{WdlArray, WdlString} import cromwell.engine._ -import cromwell.engine.backend.{StdoutStderr, Backend} import cromwell.engine.backend.Backend.RestartableWorkflow import cromwell.engine.backend.local.LocalBackend +import cromwell.engine.backend.{Backend, StdoutStderr, TaskExecutionContext} import cromwell.engine.db.DataAccess.WorkflowInfo import cromwell.engine.db.{DataAccess, LocalCallBackendInfo} import cromwell.parser.BackendType @@ -45,8 +45,10 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { override def handleCallRestarts(restartableWorkflows: Seq[RestartableWorkflow], dataAccess: DataAccess)(implicit ec: ExecutionContext) = Future.successful(()) + override def setupCallEnvironment(call: Call, workflowDescriptor: WorkflowDescriptor): TaskExecutionContext = ??? override def executeCommand(commandLine: String, workflowDescriptor: WorkflowDescriptor, - call: Call, backendInputs: CallInputs, scopedLookupFunction: ScopedLookupFunction) = Success(Map.empty) + call: Call, backendInputs: CallInputs, scopedLookupFunction: ScopedLookupFunction, + abortFunctionRegistration: AbortFunctionRegistration) = Success(Map.empty) override def backendType: BackendType = ??? } @@ -95,7 +97,7 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { it should "create and retrieve the workflow for just reading" in { assume(canConnect || testRequired) - val workflowId = UUID.randomUUID() + val workflowId = WorkflowId(UUID.randomUUID()) val workflowInfo = new WorkflowInfo(workflowId, "source", "{}") (for { @@ -115,11 +117,11 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { it should "query a single execution status" in { assume(canConnect || testRequired) - val workflowId = UUID.randomUUID() + val workflowId = WorkflowId(UUID.randomUUID()) val workflowInfo = new WorkflowInfo(workflowId, "source", "{}") - val task = new Task("taskName", Seq.empty[Declaration], new Command(Seq.empty), Seq.empty, null, BackendType.LOCAL) + val task = new Task("taskName", Seq.empty[Declaration], Seq.empty[CommandPart], Seq.empty, null, BackendType.LOCAL) val callFqn = "fully.qualified.name" - val call = new Call(None, callFqn, task, Map.empty) + val call = new Call(None, callFqn, task, Map.empty, None) val backendInfo = new LocalCallBackendInfo(ExecutionStatus.Running, Option(123), Option(456)) (for { @@ -133,7 +135,7 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { it should "create and retrieve 3step.wdl with a 10,000 char pattern" in { assume(canConnect || testRequired) - val workflowId = UUID.randomUUID() + val workflowId = WorkflowId(UUID.randomUUID()) val sampleWdl = SampleWdl.ThreeStepLargeJson val workflowInfo = new WorkflowInfo(workflowId, sampleWdl.wdlSource(), sampleWdl.wdlJson) @@ -154,7 +156,7 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { it should "fail when saving a workflow twice" in { assume(canConnect || testRequired) - val workflowId = UUID.randomUUID() + val workflowId = WorkflowId(UUID.randomUUID()) val workflowInfo = new WorkflowInfo(workflowId, "source", "{}") (for { @@ -165,7 +167,7 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { it should "fail when updating a non-existent workflow state" in { assume(canConnect || testRequired) - val workflowId = UUID.randomUUID() + val workflowId = WorkflowId(UUID.randomUUID()) (for { _ <- dataAccess.updateWorkflowState(workflowId, WorkflowRunning) @@ -174,7 +176,7 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { it should "update and get a workflow state" in { assume(canConnect || testRequired) - val workflowId = UUID.randomUUID() + val workflowId = WorkflowId(UUID.randomUUID()) val workflowInfo = new WorkflowInfo(workflowId, "source", "{}") (for { @@ -195,7 +197,7 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { it should "get workflow state" in { assume(canConnect || testRequired) - val workflowId = UUID.randomUUID() + val workflowId = WorkflowId(UUID.randomUUID()) val workflowInfo = new WorkflowInfo(workflowId, "source", "{}") val key = new SymbolStoreKey("myScope", "myName", None, input = true) val entry = new SymbolStoreEntry(key, WdlStringType, Option(new WdlString("testStringValue"))) @@ -234,11 +236,16 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { it should s"get $spec" in { assume(canConnect || testRequired) - val workflowId = UUID.randomUUID() + val workflowId = WorkflowId(UUID.randomUUID()) val workflowInfo = new WorkflowInfo(workflowId, "source", "{}") - val task = new Task("taskName", Seq.empty[Declaration], new Command(Seq.empty), Seq.empty, null, BackendType.LOCAL) - val call = new Call(callAlias, "call.name", task, Map.empty) - if (setCallParent) new Workflow("workflow.name", Seq.empty[Declaration], Seq(call)) + + val task = new Task("taskName", Seq.empty[Declaration], Seq.empty[CommandPart], Seq.empty, null, BackendType.LOCAL) + val call = if (setCallParent) { + val w = new Workflow("workflow.name", Seq.empty[Declaration], None, Seq.empty[WorkflowOutputDeclaration]) + val c = new Call(callAlias, "call.name", task, Map.empty, Option(w)) + w.setChildren(Seq(c)) + c + } else new Call(callAlias, "call.name", task, Map.empty, None) def optionallyUpdateExecutionStatus() = if (updateStatus) @@ -263,19 +270,19 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { it should "fail to get an non-existent execution status" in { assume(canConnect || testRequired) - dataAccess.getExecutionStatuses(UUID.randomUUID()).failed.futureValue should be(a[NoSuchElementException]) + dataAccess.getExecutionStatuses(WorkflowId(UUID.randomUUID())).failed.futureValue should be(a[NoSuchElementException]) } it should "get a symbol input" in { assume(canConnect || testRequired) val callFqn = "call.fully.qualified.scope" val symbolFqn = "symbol.fully.qualified.scope" - val workflowId = UUID.randomUUID() + val workflowId = WorkflowId(UUID.randomUUID()) val workflowInfo = new WorkflowInfo(workflowId, "source", "{}") val key = new SymbolStoreKey(callFqn, symbolFqn, None, input = true) val entry = new SymbolStoreEntry(key, WdlStringType, Option(new WdlString("testStringValue"))) - val task = new Task("taskName", Seq.empty[Declaration], new Command(Seq.empty), Seq.empty, null, BackendType.LOCAL) - val call = new Call(None, callFqn, task, Map.empty) + val task = new Task("taskName", Seq.empty[Declaration], Seq.empty[CommandPart], Seq.empty, null, BackendType.LOCAL) + val call = new Call(None, callFqn, task, Map.empty, None) (for { _ <- dataAccess.createWorkflow(workflowInfo, Seq(entry), Seq.empty, localBackend) @@ -286,7 +293,7 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { val resultSymbolStoreKey = resultSymbol.key resultSymbolStoreKey.scope should be("call.fully.qualified.scope") resultSymbolStoreKey.name should be("symbol.fully.qualified.scope") - resultSymbolStoreKey.iteration should be(None) + resultSymbolStoreKey.index should be(None) resultSymbolStoreKey.input should be(right = true) // IntelliJ highlighting resultSymbol.wdlType should be(WdlStringType) resultSymbol.wdlValue shouldNot be(empty) @@ -301,12 +308,12 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { val wdlArray = new WdlArray(WdlArrayType(WdlStringType), Seq(WdlString("test"), WdlString("*" * 10000))) val callFqn = "call.fully.qualified.scope" val symbolFqn = "symbol.fully.qualified.scope" - val workflowId = UUID.randomUUID() + val workflowId = WorkflowId(UUID.randomUUID()) val workflowInfo = new WorkflowInfo(workflowId, "source", "{}") val key = new SymbolStoreKey(callFqn, symbolFqn, None, input = true) val entry = new SymbolStoreEntry(key, WdlArrayType(WdlStringType), Option(wdlArray)) - val task = new Task("taskName", Seq.empty[Declaration], new Command(Seq.empty), Seq.empty, null, BackendType.LOCAL) - val call = new Call(None, callFqn, task, Map.empty) + val task = new Task("taskName", Seq.empty[Declaration], Seq.empty[CommandPart], Seq.empty, null, BackendType.LOCAL) + val call = new Call(None, callFqn, task, Map.empty, None) (for { _ <- dataAccess.createWorkflow(workflowInfo, Seq(entry), Seq.empty, localBackend) @@ -317,7 +324,7 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { val resultSymbolStoreKey = resultSymbol.key resultSymbolStoreKey.scope should be("call.fully.qualified.scope") resultSymbolStoreKey.name should be("symbol.fully.qualified.scope") - resultSymbolStoreKey.iteration should be(None) + resultSymbolStoreKey.index should be(None) resultSymbolStoreKey.input should be(right = true) // IntelliJ highlighting resultSymbol.wdlType should be(WdlArrayType(WdlStringType)) resultSymbol.wdlValue shouldNot be(empty) @@ -328,7 +335,7 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { it should "fail to get inputs for a null call" in { assume(canConnect || testRequired) - val workflowId = UUID.randomUUID() + val workflowId:WorkflowId = WorkflowId(UUID.randomUUID()) val workflowInfo = new WorkflowInfo(workflowId, "source", "{}") (for { @@ -342,10 +349,10 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { assume(canConnect || testRequired) val callFqn = "call.fully.qualified.scope" val symbolLqn = "symbol" - val workflowId = UUID.randomUUID() + val workflowId = WorkflowId(UUID.randomUUID()) val workflowInfo = new WorkflowInfo(workflowId, "source", "{}") - val task = new Task("taskName", Seq.empty[Declaration], new Command(Seq.empty), Seq.empty, null, BackendType.LOCAL) - val call = new Call(None, callFqn, task, Map.empty) + val task = new Task("taskName", Seq.empty[Declaration], Seq.empty[CommandPart], Seq.empty, null, BackendType.LOCAL) + val call = new Call(None, callFqn, task, Map.empty, None) (for { _ <- dataAccess.createWorkflow(workflowInfo, Seq.empty, Seq.empty, localBackend) @@ -357,7 +364,7 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { val resultSymbolStoreKey = resultSymbol.key resultSymbolStoreKey.scope should be("call.fully.qualified.scope") resultSymbolStoreKey.name should be("symbol") - resultSymbolStoreKey.iteration should be(None) + resultSymbolStoreKey.index should be(None) resultSymbolStoreKey.input should be(right = false) // IntelliJ highlighting resultSymbol.wdlType should be(WdlStringType) resultSymbol.wdlValue shouldNot be(empty) @@ -370,10 +377,10 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { assume(canConnect || testRequired) val callFqn = "call.fully.qualified.scope" val symbolLqn = "symbol" - val workflowId = UUID.randomUUID() + val workflowId = WorkflowId(UUID.randomUUID()) val workflowInfo = new WorkflowInfo(workflowId, "source", "{}") - val task = new Task("taskName", Seq.empty[Declaration], new Command(Seq.empty), Seq.empty, null, BackendType.LOCAL) - val call = new Call(None, callFqn, task, Map.empty) + val task = new Task("taskName", Seq.empty[Declaration], Seq.empty[CommandPart], Seq.empty, null, BackendType.LOCAL) + val call = new Call(None, callFqn, task, Map.empty, None) (for { _ <- dataAccess.createWorkflow(workflowInfo, Seq.empty, Seq.empty, localBackend) @@ -385,7 +392,7 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { val resultSymbolStoreKey = resultSymbol.key resultSymbolStoreKey.scope should be("call.fully.qualified.scope") resultSymbolStoreKey.name should be("symbol") - resultSymbolStoreKey.iteration should be(None) + resultSymbolStoreKey.index should be(None) resultSymbolStoreKey.input should be(right = false) // IntelliJ highlighting resultSymbol.wdlType should be(WdlStringType) resultSymbol.wdlValue shouldNot be(empty) @@ -396,7 +403,7 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { it should "fail to get outputs for a null call" in { assume(canConnect || testRequired) - val workflowId = UUID.randomUUID() + val workflowId = WorkflowId(UUID.randomUUID()) val workflowInfo = new WorkflowInfo(workflowId, "source", "{}") (for { @@ -409,10 +416,10 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { it should "fail to create workflow for an unknown backend" in { assume(canConnect || testRequired) val callFqn = "call.fully.qualified.scope" - val workflowId = UUID.randomUUID() + val workflowId = WorkflowId(UUID.randomUUID()) val workflowInfo = new WorkflowInfo(workflowId, "source", "{}") - val task = new Task("taskName", Seq.empty[Declaration], new Command(Seq.empty), Seq.empty, null, BackendType.LOCAL) - val call = new Call(None, callFqn, task, Map.empty) + val task = new Task("taskName", Seq.empty[Declaration], Seq.empty[CommandPart], Seq.empty, null, BackendType.LOCAL) + val call = new Call(None, callFqn, task, Map.empty, None) dataAccess.createWorkflow(workflowInfo, Seq.empty, Seq(call), UnknownBackend).failed.futureValue should be(an[IllegalArgumentException]) @@ -421,10 +428,10 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { it should "fail to create workflow for a null backend" in { assume(canConnect || testRequired) val callFqn = "call.fully.qualified.scope" - val workflowId = UUID.randomUUID() + val workflowId = WorkflowId(UUID.randomUUID()) val workflowInfo = new WorkflowInfo(workflowId, "source", "{}") - val task = new Task("taskName", Seq.empty[Declaration], new Command(Seq.empty), Seq.empty, null, BackendType.LOCAL) - val call = new Call(None, callFqn, task, Map.empty) + val task = new Task("taskName", Seq.empty[Declaration], Seq.empty[CommandPart], Seq.empty, null, BackendType.LOCAL) + val call = new Call(None, callFqn, task, Map.empty, None) dataAccess.createWorkflow(workflowInfo, Seq.empty, Seq(call), null).failed.futureValue should be(an[IllegalArgumentException]) @@ -435,12 +442,12 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { val callFqn = "call.fully.qualified.scope" val symbolLqn = "symbol" val symbolFqn = callFqn + "." + symbolLqn - val workflowId = UUID.randomUUID() + val workflowId = WorkflowId(UUID.randomUUID()) val workflowInfo = new WorkflowInfo(workflowId, "source", "{}") val key = new SymbolStoreKey(callFqn, symbolFqn, None, input = true) val entry = new SymbolStoreEntry(key, WdlStringType, Option(new WdlString("testStringValue"))) - val task = new Task("taskName", Seq.empty[Declaration], new Command(Seq.empty), Seq.empty, null, BackendType.LOCAL) - val call = new Call(None, callFqn, task, Map.empty) + val task = new Task("taskName", Seq.empty[Declaration], Seq.empty[CommandPart], Seq.empty, null, BackendType.LOCAL) + val call = new Call(None, callFqn, task, Map.empty, None) (for { _ <- dataAccess.createWorkflow(workflowInfo, Seq(entry), Seq.empty, localBackend) @@ -452,7 +459,7 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { val resultSymbolStoreKey = resultSymbol.key resultSymbolStoreKey.scope should be("call.fully.qualified.scope") resultSymbolStoreKey.name should be("symbol") - resultSymbolStoreKey.iteration should be(None) + resultSymbolStoreKey.index should be(None) resultSymbolStoreKey.input should be(right = false) // IntelliJ highlighting resultSymbol.wdlType should be(WdlStringType) resultSymbol.wdlValue shouldNot be(empty) @@ -466,12 +473,12 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { val callFqn = "call.fully.qualified.scope" val symbolLqn = "symbol" val symbolFqn = callFqn + "." + symbolLqn - val workflowId = UUID.randomUUID() + val workflowId = WorkflowId(UUID.randomUUID()) val workflowInfo = new WorkflowInfo(workflowId, "source", "{}") val key = new SymbolStoreKey(callFqn, symbolFqn, None, input = false) val entry = new SymbolStoreEntry(key, WdlStringType, Option(new WdlString("testStringValue"))) - val task = new Task("taskName", Seq.empty[Declaration], new Command(Seq.empty), Seq.empty, null, BackendType.LOCAL) - val call = new Call(None, callFqn, task, Map.empty) + val task = new Task("taskName", Seq.empty[Declaration], Seq.empty[CommandPart], Seq.empty, null, BackendType.LOCAL) + val call = new Call(None, callFqn, task, Map.empty, None) (for { _ <- dataAccess.createWorkflow(workflowInfo, Seq(entry), Seq.empty, localBackend) @@ -482,10 +489,10 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { it should "set and get a backend info" in { assume(canConnect || testRequired) - val workflowId = UUID.randomUUID() + val workflowId = WorkflowId(UUID.randomUUID()) val workflowInfo = new WorkflowInfo(workflowId, "source", "{}") - val task = new Task("taskName", Seq.empty[Declaration], new Command(Seq.empty), Seq.empty, null, BackendType.LOCAL) - val call = new Call(None, "fully.qualified.name", task, Map.empty) + val task = new Task("taskName", Seq.empty[Declaration], Seq.empty[CommandPart], Seq.empty, null, BackendType.LOCAL) + val call = new Call(None, "fully.qualified.name", task, Map.empty, None) val backendInfo = new LocalCallBackendInfo(ExecutionStatus.Running, Option(123), Option(456)) (for { @@ -507,12 +514,12 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { // Queries use `.head` a lot. There was a bug that pulled the backend info by fqn, but for any workflow. it should "set and get a backend info for same call on two workflows" in { assume(canConnect || testRequired) - val workflowId1 = UUID.randomUUID() - val workflowId2 = UUID.randomUUID() + val workflowId1 = WorkflowId(UUID.randomUUID()) + val workflowId2 = WorkflowId(UUID.randomUUID()) val workflowInfo1 = new WorkflowInfo(workflowId1, "source", "{}") val workflowInfo2 = new WorkflowInfo(workflowId2, "source", "{}") - val task = new Task("taskName", Seq.empty[Declaration], new Command(Seq.empty), Seq.empty, null, BackendType.LOCAL) - val call = new Call(None, "fully.qualified.name", task, Map.empty) + val task = new Task("taskName", Seq.empty[Declaration], Seq.empty[CommandPart], Seq.empty, null, BackendType.LOCAL) + val call = new Call(None, "fully.qualified.name", task, Map.empty, None) val backendInfo1 = new LocalCallBackendInfo(ExecutionStatus.Running, Option(123), Option(456)) val backendInfo2 = new LocalCallBackendInfo(ExecutionStatus.Failed, Option(321), Option(654)) @@ -546,10 +553,10 @@ class SlickDataAccessSpec extends FlatSpec with Matchers with ScalaFutures { it should "fail to set null backend info" in { assume(canConnect || testRequired) - val workflowId = UUID.randomUUID() + val workflowId = WorkflowId(UUID.randomUUID()) val workflowInfo = new WorkflowInfo(workflowId, "source", "{}") - val task = new Task("taskName", Seq.empty[Declaration], new Command(Seq.empty), Seq.empty, null, BackendType.LOCAL) - val call = new Call(None, "fully.qualified.name", task, Map.empty) + val task = new Task("taskName", Seq.empty[Declaration], Seq.empty[CommandPart], Seq.empty, null, BackendType.LOCAL) + val call = new Call(None, "fully.qualified.name", task, Map.empty, None) (for { _ <- dataAccess.createWorkflow(workflowInfo, Seq.empty, Seq(call), localBackend) diff --git a/src/test/scala/cromwell/engine/workflow/SingleWorkflowRunnerActorSpec.scala b/src/test/scala/cromwell/engine/workflow/SingleWorkflowRunnerActorSpec.scala index 28e8303beca..f855ea109b8 100644 --- a/src/test/scala/cromwell/engine/workflow/SingleWorkflowRunnerActorSpec.scala +++ b/src/test/scala/cromwell/engine/workflow/SingleWorkflowRunnerActorSpec.scala @@ -1,13 +1,8 @@ package cromwell.engine.workflow -import com.typesafe.config.ConfigFactory -import cromwell.engine.backend.Backend -import cromwell.{CromwellSpec, CromwellTestkitSpec} -import cromwell.engine.db.DataAccess import cromwell.util.SampleWdl.ThreeStep +import cromwell.{CromwellSpec, CromwellTestkitSpec} -import scala.concurrent.Await -import scala.concurrent.duration.Duration import scala.language.postfixOps class SingleWorkflowRunnerActorSpec extends CromwellTestkitSpec("SingleWorkflowRunnerActorSpec") { diff --git a/src/test/scala/cromwell/util/SampleWdl.scala b/src/test/scala/cromwell/util/SampleWdl.scala index 51c85ff5dac..bfdf0c907c2 100644 --- a/src/test/scala/cromwell/util/SampleWdl.scala +++ b/src/test/scala/cromwell/util/SampleWdl.scala @@ -46,6 +46,7 @@ object SampleWdl { override def wdlSource(runtime: String = "") = """ |task hello { + | String addressee | command { | echo "Hello ${addressee}!" | } @@ -69,6 +70,7 @@ object SampleWdl { override def wdlSource(runtime: String = "") = """ |task hello { + | String addressee | command { | echo "Hello ${addressee}!" | } @@ -109,8 +111,9 @@ object SampleWdl { override def wdlSource(runtime: String = "") = """ |task incr { + | Int val | command { - | echo $((${Int val} + 1)) + | echo $((${val} + 1)) | } | output { | Int out = read_int(stdout()) @@ -122,13 +125,14 @@ object SampleWdl { |} """.stripMargin - override val rawInputs: WorkflowRawInputs = Map("incr.incr.val" -> "1") + override val rawInputs: WorkflowRawInputs = Map("incr.incr.val" -> "x1") } object SubtractionWorkflow { val WdlSource = """ |task a { + | String message | command { echo '${message}' } | output { | String message = read_string(stdout()) @@ -151,6 +155,7 @@ object SampleWdl { override def wdlSource(runtime: String = "") = { """ |task summary { + | String bfile | command { | ~/plink --bfile ${bfile} --missing --hardy --out foo --allow-no-sex | } @@ -166,7 +171,6 @@ object SampleWdl { | } |} | - | |workflow test1 { | call summary { | input: bfile=bfile @@ -191,8 +195,11 @@ object SampleWdl { |} | |task cgrep { + | String pattern + | File in_file + | | command { - | grep '${pattern}' ${File in_file} | wc -l + | grep '${pattern}' ${in_file} | wc -l | } | output { | Int count = read_int(stdout()) @@ -200,8 +207,9 @@ object SampleWdl { |} | |task wc { + | File in_file | command { - | cat ${File in_file} | wc -l + | cat ${in_file} | wc -l | } | output { | Int count = read_int(stdout()) @@ -224,6 +232,79 @@ object SampleWdl { override val rawInputs = Map(PatternKey -> "...") } + object ScatterWdl extends SampleWdl { + override def wdlSource(runtime: String = "") = + """ + task A { + | command { + | echo -n -e "jeff\nchris\nmiguel\nthibault\nkhalid\nscott" + | } + | output { + | Array[String] A_out = read_lines(stdout()) + | } + |} + | + |task B { + | String B_in + | command { + | python -c "print(len('${B_in}'))" + | } + | output { + | Int B_out = read_int(stdout()) + | } + |} + | + |task C { + | Int C_in + | command { + | python -c "print(${C_in}*100)" + | } + | output { + | Int C_out = read_int(stdout()) + | } + |} + | + |task D { + | Array[Int] D_in + | command { + | python -c "print(${sep='+' D_in})" + | } + | output { + | Int D_out = read_int(stdout()) + | } + |} + | + |task E { + | command { + | python -c "import random; print(random.randint(1,100))" + | } + | output { + | Int E_out = read_int(stdout()) + | } + |} + | + |workflow w { + | call A + | scatter (item in A.A_out) { + | call B {input: B_in=item} + | call C {input: C_in=B.B_out} + | call E + | scatter (itemB in B.B_out) { + | call E as G + | } + | scatter (itemB in B.B_out) { + | call E as H + | } + | } + | scatter (item in A.A_out) { + | call E as F + | } + | call D {input: D_in=B.B_out} + |} + """.stripMargin + override lazy val rawInputs = Map("" -> "...") + } + object ThreeStepLargeJson extends SampleWdl { override def wdlSource(runtime: String = "") = ThreeStep.wdlSource(runtime) override lazy val rawInputs = Map(ThreeStep.PatternKey -> "." * 10000) @@ -233,8 +314,9 @@ object SampleWdl { override def wdlSource(runtime: String): WdlSource = """ |task hello { + | String? person | command { - | echo "hello ${person?}" + | echo "hello ${person}" | } | output { | String greeting = read_string(stdout()) @@ -260,8 +342,9 @@ object SampleWdl { override def wdlSource(runtime: String): WdlSource = """ |task hello { + | Array[String] person | command { - | echo "hello ${sep="," person*}" + | echo "hello ${sep="," person}" | } | output { | String greeting = read_string(stdout()) @@ -278,20 +361,21 @@ object SampleWdl { override val rawInputs = Map("postfix.hello.person" -> Seq("alice", "bob", "charles")) } - object ZeroOrMorePostfixQuantifierWorkflowWithScalarInput extends ZeroOrMorePostfixQuantifier { - override val rawInputs = Map("postfix.hello.person" -> "alice") + object ZeroOrMorePostfixQuantifierWorkflowWithOneElementArrayInput extends ZeroOrMorePostfixQuantifier { + override val rawInputs = Map("postfix.hello.person" -> Seq("alice")) } - object ZeroOrMorePostfixQuantifierWorkflowWithNoInput extends ZeroOrMorePostfixQuantifier { - override val rawInputs = Map.empty[String, String] + object ZeroOrMorePostfixQuantifierWorkflowWithZeroElementArrayInput extends ZeroOrMorePostfixQuantifier { + override val rawInputs = Map("postfix.hello.person" -> Seq()) } trait OneOrMorePostfixQuantifier extends SampleWdl { override def wdlSource(runtime: String): WdlSource = """ |task hello { + | Array[String]+ person | command { - | echo "hello ${sep="," person+}" + | echo "hello ${sep="," person}" | } | output { | String greeting = read_string(stdout()) @@ -309,15 +393,16 @@ object SampleWdl { } object OneOrMorePostfixQuantifierWorkflowWithScalarInput extends OneOrMorePostfixQuantifier { - override val rawInputs = Map("postfix.hello.person" -> "alice") + override val rawInputs = Map("postfix.hello.person" -> Seq("alice")) } trait DefaultParameterValue extends SampleWdl { override def wdlSource(runtime: String): WdlSource = """ |task hello { + | String? person | command { - | echo "hello ${default="default value" person?}" + | echo "hello ${default="default value" person}" | } | output { | String greeting = read_string(stdout()) @@ -351,8 +436,9 @@ object SampleWdl { override def wdlSource(runtime: String): WdlSource = """ |task ps { + | File dummy_ps_file | command { - | cat ${File dummy_ps_file} + | cat ${dummy_ps_file} | } | output { | File procs = stdout() @@ -361,8 +447,10 @@ object SampleWdl { |} | |task cgrep { + | String pattern + | File in_file | command { - | grep '${pattern}' ${File in_file} | wc -l + | grep '${pattern}' ${in_file} | wc -l | } | output { | Int count = read_int(stdout()) @@ -371,8 +459,9 @@ object SampleWdl { |} | |task wc { + | File in_file | command { - | cat ${File in_file} | wc -l + | cat ${in_file} | wc -l | } | output { | Int count = read_int(stdout()) @@ -428,8 +517,10 @@ object SampleWdl { |} | |task cgrep { + | String pattern + | File in_file | command { - | grep '${pattern}' ${File in_file} | wc -l + | grep '${pattern}' ${in_file} | wc -l | } | output { | Int count = read_int(stdout()) @@ -440,8 +531,9 @@ object SampleWdl { |} | |task wc { + | File in_file | command { - | cat ${File in_file} | wc -l + | cat ${in_file} | wc -l | } | output { | Int count = read_int(stdout()) @@ -499,8 +591,10 @@ object SampleWdl { |} | |task cgrep { + | String pattern + | File in_file | command { - | grep '${pattern}' ${File in_file} | wc -l + | grep '${pattern}' ${in_file} | wc -l | } | output { | Int count = stdout() @@ -508,8 +602,9 @@ object SampleWdl { |} | |task wc { + | File in_file | command { - | cat ${File in_file} | wc -l + | cat ${in_file} | wc -l | } | output { | Int count = read_int(stdout()) @@ -543,8 +638,9 @@ object SampleWdl { override def wdlSource(runtime: String): WdlSource = """ |task cat_to_stdout { + | File file | command { - | cat ${File file} + | cat ${file} | } | output { | Array[String] lines = read_lines(stdout()) @@ -553,8 +649,9 @@ object SampleWdl { |} | |task cat_to_file { + | File file | command { - | cat ${File file} > out + | cat ${file} > out | } | output { | Array[String] lines = read_lines("out") @@ -580,8 +677,10 @@ object SampleWdl { override def wdlSource(runtime: String): WdlSource = """ |task cat { + | File file + | String? flags | command { - | cat ${flags?} ${File file} + | cat ${flags} ${file} | } | output { | File procs = stdout() @@ -590,8 +689,10 @@ object SampleWdl { | |task cgrep { | String str_decl + | String pattern + | File in_file | command { - | grep '${pattern}' ${File in_file} | wc -l + | grep '${pattern}' ${in_file} | wc -l | } | output { | Int count = read_int(stdout()) @@ -629,6 +730,8 @@ object SampleWdl { override def wdlSource(runtime: String = "") = """ |task echo { + | String greeting + | String out | command { | echo "${greeting}" > ${out}.txt | } @@ -652,8 +755,10 @@ object SampleWdl { object ArrayIO extends SampleWdl { override def wdlSource(runtime: String = "") = """task concat_files { + | String? flags + | Array[File]+ files | command { - | cat ${default="-s" flags?} ${sep=" " File files+} + | cat ${default="-s" flags} ${sep=" " files} | } | output { | File concatenated = stdout() @@ -661,8 +766,10 @@ object SampleWdl { |} | |task find { + | String pattern + | File root | command { - | find ${File root} ${"-name " pattern?} + | find ${root} ${"-name " + pattern} | } | output { | Array[String] results = read_lines(stdout()) @@ -670,16 +777,31 @@ object SampleWdl { |} | |task count_lines { + | Array[File]+ files | command { - | cat ${sep=' ' File files+} | wc -l + | cat ${sep=' ' files} | wc -l | } | output { | Int count = read_int(stdout()) | } |} | + |task serialize { + | Array[String] strs + | command { + | cat ${write_lines(strs)} + | } + | output { + | String contents = read_string(stdout()) + | } + |} + | |workflow wf { | Array[File] files + | Array[String] strings = ["str1", "str2", "str3"] + | call serialize { + | input: strs=strings + | } | call concat_files as concat { | input: files=files | } @@ -718,8 +840,9 @@ object SampleWdl { override def wdlSource(runtime: String = "") = """ |task cat { + | Array[File]+ files | command { - | cat -s ${sep=' ' File files+} + | cat -s ${sep=' ' files} | } | output { | Array[String] lines = read_lines(stdout()) @@ -735,6 +858,41 @@ object SampleWdl { override val rawInputs = Map.empty[String, String] } + case object MapLiteral extends SampleWdl { + override def wdlSource(runtime: String = "") = + """ + |task write_map { + | Map[File, String] file_to_name + | command { + | cat ${write_map(file_to_name)} + | } + | output { + | String contents = read_string(stdout()) + | } + |} + | + |task read_map { + | command <<< + | python <>> + | output { + | Map[String, Int] out_map = read_map(stdout()) + | } + |} + | + |workflow wf { + | Map[File, String] map = {"f1": "alice", "f2": "bob", "f3": "chuck"} + | call write_map {input: file_to_name=map} + | call read_map + |} + """.stripMargin + + override val rawInputs = Map.empty[String, String] + } + object MultiLineCommandWorkflowWdl extends SampleWdl { override def wdlSource(runtime: String = "") = """task blah { @@ -760,4 +918,61 @@ object SampleWdl { override val rawInputs = Map.empty[String, String] } + + object TripleSleep extends SampleWdl { + override def wdlSource(runtime: String = "") = + """ + |task wait { + | command <<< + | sleep 100 + | echo "waited 100 seconds" + | >>> + | output { + | String intermediate = read_string(stdout()) + | } + |} + |task msg { + | command { + | echo ${sommat} + | } + | output { + | String result = read_string(stdout()) + | } + |} + | + |workflow hello { + | call wait as wait1 + | call wait as wait2 + | call wait as wait3 + | + | call msg as msg1 {input: sommat = wait1.intermediate} + | call msg as msg2 {input: sommat = wait2.intermediate} + | call msg as msg3 {input: sommat = wait3.intermediate} + |} + """.stripMargin + + override val rawInputs = Map.empty[String, String] + val OutputKey1 = "hello.msg1.result" + val OutputValue = "waited 100 seconds" + } + + object BadTaskOutputWdl extends SampleWdl { + override def wdlSource(runtime: String): WdlSource = + """task bad { + | command { + | echo "hello" > a + | } + | output { + | # Oops! we made a spelling mistake in our WDL! + | File a = "b" + | } + |} + | + |workflow badExample { + | call bad + |} + """.stripMargin + + override val rawInputs = Map.empty[String, String] + } } diff --git a/src/test/scala/cromwell/webservice/CromwellApiServiceSpec.scala b/src/test/scala/cromwell/webservice/CromwellApiServiceSpec.scala index 8ed930c941d..f60953739ea 100644 --- a/src/test/scala/cromwell/webservice/CromwellApiServiceSpec.scala +++ b/src/test/scala/cromwell/webservice/CromwellApiServiceSpec.scala @@ -26,11 +26,11 @@ object MockWorkflowManagerActor { case class WorkflowStatus(id: WorkflowId) extends WorkflowManagerMessage case class WorkflowOutputs(id: WorkflowId) extends WorkflowManagerMessage - val createdWorkflowId = UUID.randomUUID() - val runningWorkflowId = UUID.randomUUID() - val unknownId = UUID.randomUUID() - val submittedWorkflowId = UUID.randomUUID() - val abortedWorkflowId = UUID.randomUUID() + val createdWorkflowId = WorkflowId(UUID.randomUUID()) + val runningWorkflowId = WorkflowId(UUID.randomUUID()) + val unknownId = WorkflowId(UUID.randomUUID()) + val submittedWorkflowId = WorkflowId(UUID.randomUUID()) + val abortedWorkflowId = WorkflowId(UUID.randomUUID()) def props: Props = Props(classOf[MockWorkflowManagerActor]) }