diff --git a/corpus/run.txt b/corpus/run.txt index d7ebf75..3595d6a 100644 --- a/corpus/run.txt +++ b/corpus/run.txt @@ -57,3 +57,24 @@ run ["echo", "test"] (double_quoted_string) (double_quoted_string)))) +================== +Run with options +================== + +run --mount=type=secret,id=aws,target=/root/.aws/credentials \ + --security=insecure \ + aws s3 cp s3://example.com + +--- + +(source_file + (run_instruction + (mount_param + (mount_param_param) + (mount_param_param) + (mount_param_param)) + (line_continuation) + (param) + (line_continuation) + (shell_command + (shell_fragment)))) diff --git a/grammar.js b/grammar.js index 8337468..7189693 100644 --- a/grammar.js +++ b/grammar.js @@ -40,6 +40,12 @@ module.exports = grammar({ run_instruction: ($) => seq( alias(/[rR][uU][nN]/, "RUN"), + repeat( + choice( + $.param, + $.mount_param + ) + ), choice($.string_array, $.shell_command) ), @@ -266,6 +272,7 @@ module.exports = grammar({ repeat1(choice(token.immediate(/[a-zA-Z0-9:]+/), $._immediate_expansion)) ), + // Generic parsing of options passed right after an instruction name. param: ($) => seq( "--", @@ -274,6 +281,31 @@ module.exports = grammar({ field("value", token.immediate(/[^\s]+/)) ), + // Specific parsing of the --mount option e.g. + // + // --mount=type=cache,target=/root/.cache/go-build + // + mount_param: ($) => seq( + "--", + field("name", token.immediate("mount")), + token.immediate("="), + field( + "value", + seq( + $.mount_param_param, + repeat( + seq(token.immediate(","), $.mount_param_param) + ) + ) + ) + ), + + mount_param_param: ($) => seq( + token.immediate(/[^\s=,]+/), + token.immediate("="), + token.immediate(/[^\s=,]+/) + ), + image_alias: ($) => seq( choice(/[-a-zA-Z0-9_]+/, $.expansion), repeat(choice(token.immediate(/[-a-zA-Z0-9_]+/), $._immediate_expansion)) @@ -301,7 +333,24 @@ module.exports = grammar({ ) ), - shell_fragment: ($) => repeat1(choice(/[^\\\[\n#\s][^\\\n]*/, /\\[^\n]/)), + shell_fragment: ($) => repeat1( + choice( + // A shell fragment is broken into the same tokens as other + // constructs because the lexer prefers the longer tokens + // when it has a choice. The example below shows the tokenization + // of the --mount parameter. + // + // RUN --mount=foo=bar,baz=42 ls --all + // ^^ ^ ^ ^ ^ + // ^^^^^ ^^^ ^^^ ^^^ ^^ + // |--------param-------| + // |--shell_command--| + // + /[,=-]/, + /[^\\\[\n#\s,=-][^\\\n]*/, + /\\[^\n,=-]/ + ) + ), line_continuation: ($) => "\\\n", required_line_continuation: ($) => "\\\n",