| { |
| "scenario": "Syntax errors with character offsets", |
| "description": "Syntax errors; for ICU4C, the character offset in the parse error is checked", |
| "defaultTestProperties": { |
| "locale": "en-US", |
| "expErrors": [ |
| { |
| "type": "syntax-error" |
| } |
| ] |
| }, |
| "tests": [ |
| { "src": "}{|xyz|", "char": 0 }, |
| { "src": "}", "char": 0 }, |
| { |
| "src": "{{{%\\y{}}", |
| "char": 5, |
| "comment": "Backslash followed by non-backslash followed by a '{' -- this should be an error immediately after the first backslash" |
| }, |
| { |
| "src": "{%abc|\\z}}", |
| "char": 7, |
| "comment": "Reserved chars followed by a '|' that doesn't begin a valid literal -- this should be an error at the first invalid char in the literal" |
| }, |
| { |
| "src": "{%\\y{p}}", |
| "char": 3, |
| "comment": "Same pattern, but with a valid reserved-char following the erroneous reserved-escape -- the offset should be the same as with the previous one" |
| }, |
| { |
| "src": "{{{%ab|\\z|cd}}", |
| "char": 8, |
| "comment": "Erroneous literal inside a reserved string -- the error should be at the first erroneous literal char" |
| }, |
| { |
| "src": "hello {|4.2| %num\\ber}}", |
| "char": 18, |
| "comment": "Single backslash not allowed" |
| }, |
| { |
| "src": "hello {|4.2| %num{be\\|r}}", |
| "char": 17, |
| "comment": "Unescaped '{' not allowed" |
| }, |
| { |
| "src": "hello {|4.2| %num}be\\|r}}", |
| "char": 23, |
| "comment": "Unescaped '}' -- will be interpreted as the end of the reserved string, and the error will be reported at the index of the next '}'" }, |
| { |
| "src": "hello {|4.2| %num\\{be|r}}", |
| "char": 25, |
| "comment": "Unescaped '|' -- will be interpreted as the beginning of a literal. Error at end of input" |
| }, |
| { |
| "src": ".match{|y|}|y|{{{|||}}}", |
| "char": 19, |
| "comment": "No spaces are required here. The error should be in the pattern, not before" |
| }, |
| { |
| "src": ".match {|y|}|foo|bar {{{a}}}", |
| "char": 17, |
| "comment": "Missing spaces between keys" |
| }, |
| { |
| "src": ".match {|y|} |quux| |foo|bar {{{a}}}", |
| "char": 25, |
| "comment": "Missing spaces between keys" |
| }, |
| { |
| "src": ".match {|y|} |quux| |foo||bar| {{{a}}}", |
| "char": 26, |
| "comment": "Missing spaces between keys" |
| }, |
| { |
| "src": ".match {|y|} |\\q| * %{! {z}", |
| "char": 16, |
| "comment": "Error parsing the first key -- the error should be there, not in the also-erroneous third key" |
| }, |
| { |
| "src": ".match {|y|} * %{! {z} |\\q|", |
| "char": 16, |
| "comment": "Error parsing the second key -- the error should be there, not in the also-erroneous third key" |
| }, |
| { |
| "src": ".match {|y|} * |\\q| {\\z}", |
| "char": 18, |
| "comment": "Error parsing the last key -- the error should be there, not in the erroneous pattern" |
| }, |
| { |
| "src": ".match {|y|} {\\|} {@} * * * {{a}}", |
| "char": 14, |
| "comment": "Non-expression as scrutinee in pattern -- error should be at the first non-expression, not the later non-expression" |
| }, |
| { |
| "src": ".match {|y|} $foo * {{a}} when * :bar {{b}}", |
| "char": 14, |
| "comment": "Non-key in variant -- error should be there, not in the next erroneous variant" |
| }, |
| { |
| "src": "{{ foo {|bar|} \\q baz ", |
| "char": 16, |
| "comment": "Error should be within the first erroneous `text` or expression" |
| }, |
| { |
| "src": "{{{: }}}", |
| "char": 4, |
| "comment": "':' has to be followed by a function name -- the error should be at the first whitespace character" |
| }, |
| { |
| "src": ".local $x = }|foo|}", |
| "char": 12, |
| "comment": "Expression not starting with a '{'" |
| }, |
| { |
| "src": ".local $bar {|foo|} {{$bar}}", |
| "char": 12, |
| "comment": "Missing '=' in `.local` declaration" |
| }, |
| { |
| "src": ".local bar = {|foo|} {{$bar}}", |
| "char": 7, |
| "comment": "LHS of declaration doesn't start with a '$'" |
| }, |
| { |
| "src": ".local $bar = |foo| {{$bar}}", |
| "char": 14, |
| "comment": "`.local` RHS isn't an expression" |
| }, |
| { |
| "src": "{{extra}}content", |
| "char": 9, |
| "comment": "Trailing characters that are not whitespace" |
| }, |
| { |
| "src": ".match {|x|} * {{foo}}extra", |
| "char": 28, |
| "comment": "Trailing characters that are not whitespace" |
| }, |
| { |
| "src": "empty { }", |
| "char": 8, |
| "comment": "Empty expression" |
| }, |
| { |
| "src": ".match {} * {{foo}}", |
| "char": 8, |
| "comment": "Empty expression" |
| }, |
| { |
| "src": "bad {:}", |
| "char": 6, |
| "comment": "':' not preceding a function name" |
| }, |
| { |
| "src": "{{no-equal {|42| :number m }}}", |
| "char": 27, |
| "comment": "Missing '=' after option name" |
| }, |
| { |
| "src": "{{no-equal {|42| :number minimumFractionDigits 2}}}", |
| "char": 47, |
| "comment": "Missing '=' after option name" |
| }, |
| { |
| "src": "bad {:placeholder option value}", |
| "char": 25, |
| "comment": "Missing '=' after option name" |
| }, |
| { |
| "src": "hello {|4.2| :number min=2=3}", |
| "char": 26, |
| "comment": "Extra '=' after option name" |
| }, |
| { |
| "src": "hello {|4.2| :number min=2max=3}", |
| "char": 26, |
| "comment": "Missing space between options" |
| }, |
| { |
| "src": "hello {|4.2| :number min=|a|max=3}", |
| "char": 28, |
| "comment": "Missing whitespace between valid options" |
| }, |
| { |
| "src": "hello {|4.2| :number min=|\\a|}", |
| "char": 27, |
| "comment": "Ill-formed RHS of option -- the error should be within the RHS, not after parsing options" |
| }, |
| { |
| "src": "no-equal {|42| :number {}", |
| "char": 25, |
| "comment": "Junk after annotation" |
| }, |
| { |
| "src": "bad {:placeholder option=}", |
| "char": 25, |
| "comment": "Missing RHS of option" |
| }, |
| { |
| "src": "bad {:placeholder option}", |
| "char": 24, |
| "comment": "Missing RHS of option" |
| }, |
| { |
| "src": "bad {$placeholder option}", |
| "char": 18, |
| "comment": "Annotation is not a function or reserved text" |
| }, |
| { |
| "src": "no {$placeholder end", |
| "char": 17, |
| "comment": "Annotation is not a function or reserved text" |
| }, |
| { |
| "src": ".match * {{foo}}", |
| "char": 8, |
| "comment": "Missing expression in selectors" |
| }, |
| { |
| "src": ".match |x| * {{foo}}", |
| "char": 7, |
| "comment": "Non-expression in selectors" |
| }, |
| { |
| "src": ".match {|x|} * foo", |
| "char": 19, |
| "comment": "Missing RHS in variant" |
| }, |
| { |
| "src": "{$:abc}", |
| "char": 2, |
| "comment": "Variable names can't start with a : or -" |
| }, |
| { |
| "src": "{$-abc}", |
| "char": 2, |
| "comment": "Variable names can't start with a : or -" |
| }, |
| { |
| "src": "{|3.14|:foo}", |
| "char": 7, |
| "comment": "Missing space before annotation." |
| }, |
| { |
| "src": "{|3.14|-foo}", |
| "char": 7, |
| "comment": "Missing space before annotation." |
| }, |
| { |
| "src": "{|3.14|+foo}", |
| "char": 7, |
| "comment": "Missing space before annotation." |
| }, |
| { |
| "src": ".local $foo = {$bar} .match {$foo} :one {one} * {other}", |
| "char": 36, |
| "comment": "Unquoted literals can't begin with a ':'" |
| }, |
| { |
| "src": ".local $foo = {$bar :fun option=:a} {{bar {$foo}}}", |
| "char": 32, |
| "comment": "Unquoted literals can't begin with a ':'" |
| }, |
| { "src": "{|foo| {#markup}}", "char": 7, "comment": "Markup in wrong place" }, |
| { "src": "{|foo| #markup}", "char": 7, "comment": "Markup in wrong place" }, |
| { "src": "{|foo| {#markup/}}", "char": 7, "comment": "Markup in wrong place" }, |
| { "src": "{|foo| {/markup}}", "char": 7, "comment": "Markup in wrong place" }, |
| { "src": ".input $x = {|1|} {{{$x}}}", "char": 7, "comment": ".input with non-variable-expression" }, |
| { "src": ".input $x = {:number} {{{$x}}}", "char": 7, "comment": ".input with non-variable-expression" }, |
| { "src": ".input {|1| :number} {{{$x}}}", "char": 7, "comment": ".input with non-variable-expression" }, |
| { "src": ".input {:number} {{{$x}}}", "char": 7, "comment": ".input with non-variable-expression" }, |
| { "src": ".input {|1|} {{{$x}}}", "char": 7, "comment": ".input with non-variable-expression" }, |
| { "src": ".", "char": 1}, |
| { "src": "{", "char": 1}, |
| { "src": "}", "char": 0}, |
| { "src": "{}", "char": 1}, |
| { "src": "{{", "char": 2}, |
| { "src": "{{}", "char": 3}, |
| { "src": "{{}}}", "char": 4}, |
| { "src": "{|foo| #markup}", "char": 7}, |
| { "src": "{{missing end brace}", "char": 20}, |
| { "src": "{{missing end braces", "char": 20}, |
| { "src": "{{missing end {$braces", "char": 22}, |
| { "src": "{{extra}} content", "char": 10}, |
| { "src": "empty { } placeholder", "char": 8}, |
| { "src": "missing space {42:func}", "char": 17}, |
| { "src": "missing space {|foo|:func}", "char": 20}, |
| { "src": "missing space {|foo|@bar}", "char": 20}, |
| { "src": "missing space {:func@bar}", "char": 20}, |
| { "src": "{:func @bar@baz}", "char": 11}, |
| { "src": "{:func @bar=42@baz}", "char": 14}, |
| { "src": "{+reserved@bar}", "char": 10}, |
| { "src": "{&private@bar}", "char": 9}, |
| { "src": "bad {:} placeholder", "char": 6}, |
| { "src": "bad {\\u0000placeholder}", "char": 5}, |
| { "src": "no-equal {|42| :number minimumFractionDigits 2}", "char": 45}, |
| { "src": "bad {:placeholder option=}", "char": 25}, |
| { "src": "bad {:placeholder option value}", "char": 25}, |
| { "src": "bad {:placeholder option:value}", "char": 30}, |
| { "src": "bad {:placeholder option}", "char": 24}, |
| { "src": "bad {:placeholder:}", "char": 18}, |
| { "src": "bad {::placeholder}", "char": 6}, |
| { "src": "bad {:placeholder::foo}", "char": 18}, |
| { "src": "bad {:placeholder option:=x}", "char": 25}, |
| { "src": "bad {:placeholder :option=x}", "char": 18}, |
| { "src": "bad {:placeholder option::x=y}", "char": 25}, |
| { "src": "bad {$placeholder option}", "char": 18}, |
| { "src": "bad {:placeholder @attribute=}", "char": 29}, |
| { "src": "bad {:placeholder @attribute=@foo}", "char": 29}, |
| { "src": "no {placeholder end", "char": 16}, |
| { "src": "no {$placeholder end", "char": 17}, |
| { "src": "no {:placeholder end", "char": 20}, |
| { "src": "no {|placeholder| end", "char": 18}, |
| { "src": "no {|literal} end", "char": 17}, |
| { "src": "no {|literal or placeholder end", "char": 31}, |
| { "src": ".local bar = {|foo|} {{_}}", "char": 7}, |
| { "src": ".local #bar = {|foo|} {{_}}", "char": 7}, |
| { "src": ".local $bar {|foo|} {{_}}", "char": 12}, |
| { "src": ".local $bar = |foo| {{_}}", "char": 14}, |
| { "src": ".match {#foo} * {{foo}}", "char": 8}, |
| { "src": ".match {} * {{foo}}", "char": 8}, |
| { "src": ".match {|foo| :x} {|bar| :x} ** {{foo}}", "char": 30}, |
| { "src": ".match * {{foo}}", "char": 7}, |
| { "src": ".match {|x| :x} * foo", "char": 21}, |
| { "src": ".match {|x| :x} * {{foo}} extra", "char": 31}, |
| { "src": ".match |x| * {{foo}}", "char": 7}, |
| { "src": ".match {|foo| :string} o:ne {{one}} * {{other}}", "char": 24, "comment" : "tests for ':' in unquoted literals (not allowed)" }, |
| { "src": ".match {|foo| :string} one: {{one}} * {{other}}", "char": 26, "comment" : "tests for ':' in unquoted literals (not allowed)" }, |
| { "src": ".local $foo = {|42| :number option=a:b} {{bar {$foo}}}", "char": 36, "comment" : "tests for ':' in unquoted literals (not allowed)" }, |
| { "src": ".local $foo = {|42| :number option=a:b:c} {{bar {$foo}}}", "char": 36, "comment" : "tests for ':' in unquoted literals (not allowed)" }, |
| { "src": "{$bar:foo}", "char": 5, "comment" : "tests for ':' in unquoted literals (not allowed)"}, |
| { |
| "src": ".match {1} {{_}}", |
| "char": 12, |
| "comment": "Disambiguating a wrong .match from an unsupported statement" |
| } |
| ] |
| } |