|
1 | | -start |
2 | | - = messageFormatPattern |
| 1 | +start = token* |
3 | 2 |
|
4 | | -messageFormatPattern |
5 | | - = st:(messageFormatElement/string/octothorpe)* { |
6 | | - return { type: 'messageFormatPattern', statements: st }; |
7 | | - } |
8 | | - |
9 | | -messageFormatElement |
10 | | - = '{' _ argIdx:id efmt:(',' elementFormat)? _ '}' { |
11 | | - var res = { |
12 | | - type: "messageFormatElement", |
13 | | - argumentIndex: argIdx |
| 3 | +token |
| 4 | + = '{' _ arg:id _ '}' { |
| 5 | + return { |
| 6 | + type: 'argument', |
| 7 | + arg: arg |
14 | 8 | }; |
15 | | - if (efmt && efmt.length) { |
16 | | - res.elementFormat = efmt[1]; |
17 | | - } else { |
18 | | - res.output = true; |
19 | | - } |
20 | | - return res; |
21 | | - } |
22 | | - |
23 | | -elementFormat |
24 | | - = _ t:"plural" _ ',' _ s:pluralFormatPattern _ { |
25 | | - return { type: "elementFormat", key: t, val: s }; |
26 | 9 | } |
27 | | - / _ t:"selectordinal" _ ',' _ s:pluralFormatPattern _ { |
28 | | - return { type: "elementFormat", key: t, val: s }; |
29 | | - } |
30 | | - / _ t:"select" _ ',' _ s:selectFormatPattern _ { |
31 | | - return { type: "elementFormat", key: t, val: s }; |
32 | | - } |
33 | | - / _ t:id p:argStylePattern* { |
34 | | - return { type: "elementFormat", key: t, val: p }; |
| 10 | + / '{' _ arg:id _ ',' _ 'select' _ ',' _ cases:selectCase+ _ '}' { |
| 11 | + return { |
| 12 | + type: 'select', |
| 13 | + arg: arg, |
| 14 | + cases: cases |
| 15 | + }; |
35 | 16 | } |
36 | | - |
37 | | -pluralFormatPattern |
38 | | - = op:offsetPattern? pf:(pluralForm)+ { |
39 | | - return { type: "pluralFormatPattern", pluralForms: pf, offset: op || 0 }; |
| 17 | + / '{' _ arg:id _ ',' _ type:('plural'/'selectordinal') _ ',' _ offset:offset? cases:pluralCase+ _ '}' { |
| 18 | + return { |
| 19 | + type: type, |
| 20 | + arg: arg, |
| 21 | + offset: offset || 0, |
| 22 | + cases: cases |
| 23 | + }; |
40 | 24 | } |
41 | | - |
42 | | -offsetPattern |
43 | | - = _ "offset" _ ":" _ d:digits _ { return d; } |
44 | | - |
45 | | -pluralForm |
46 | | - = _ k:pluralKey _ "{" _ mfp:messageFormatPattern _ "}" { |
47 | | - return { key: k, val: mfp }; |
| 25 | + / '{' _ arg:id _ ',' _ key:id _ params:functionParams* '}' { |
| 26 | + return { |
| 27 | + type: 'function', |
| 28 | + arg: arg, |
| 29 | + key: key, |
| 30 | + params: params |
| 31 | + }; |
48 | 32 | } |
| 33 | + / '#' { return { type: 'octothorpe' }; } |
| 34 | + / str:char+ { return str.join(''); } |
49 | 35 |
|
50 | | -pluralKey |
51 | | - = i:id { return i; } |
52 | | - / "=" d:digits { return d; } |
| 36 | +id = $([0-9a-zA-Z$_][^ \t\n\r,.+={}]*) |
53 | 37 |
|
54 | | -selectFormatPattern |
55 | | - = pf:selectForm+ { return { type: "selectFormatPattern", pluralForms: pf }; } |
| 38 | +selectCase = _ key:id _ tokens:caseTokens { return { key: key, tokens: tokens }; } |
56 | 39 |
|
57 | | -selectForm |
58 | | - = _ k:id _ "{" _ mfp:messageFormatPattern _ "}" { |
59 | | - return { key: k, val: mfp }; |
60 | | - } |
61 | | - |
62 | | -argStylePattern |
63 | | - = _ "," _ p:id _ { return p; } |
| 40 | +pluralCase = _ key:pluralKey _ tokens:caseTokens { return { key: key, tokens: tokens }; } |
64 | 41 |
|
65 | | -octothorpe |
66 | | - = '#' { return {type: 'octothorpe'}; }; |
| 42 | +caseTokens = '{' (_ & '{')? tokens:token* _ '}' { return tokens; } |
67 | 43 |
|
68 | | -string |
69 | | - = s:(chars/whitespace)+ { return { type: "string", val: s.join('') }; } |
| 44 | +offset = _ 'offset' _ ':' _ d:digits _ { return d; } |
70 | 45 |
|
71 | | -// This is a subset to keep code size down |
72 | | -// More or less, it has to be a single word |
73 | | -// that doesn't contain punctuation, etc |
74 | | -id "identifier" |
75 | | - = _ s:$([0-9a-zA-Z$_][^ \t\n\r,.+={}]*) _ { return s; } |
| 46 | +pluralKey = id / '=' d:digits { return d; } |
76 | 47 |
|
77 | | -chars |
78 | | - = chars:char+ { return chars.join(''); } |
| 48 | +functionParams = _ ',' _ p:id _ { return p; } |
79 | 49 |
|
80 | 50 | char |
81 | | - = x:[^{}#\\\0-\x1F\x7f \t\n\r] { return x; } |
82 | | - / "\\\\" { return "\\"; } |
83 | | - / "\\#" { return "#"; } |
84 | | - / "\\{" { return "\u007B"; } |
85 | | - / "\\}" { return "\u007D"; } |
86 | | - / "\\u" h1:hexDigit h2:hexDigit h3:hexDigit h4:hexDigit { |
87 | | - return String.fromCharCode(parseInt("0x" + h1 + h2 + h3 + h4)); |
| 51 | + = [^{}#\\\0-\x08\x0e-\x1f\x7f] |
| 52 | + / '\\\\' { return '\\'; } |
| 53 | + / '\\#' { return '#'; } |
| 54 | + / '\\{' { return '\u007B'; } |
| 55 | + / '\\}' { return '\u007D'; } |
| 56 | + / '\\u' h1:hexDigit h2:hexDigit h3:hexDigit h4:hexDigit { |
| 57 | + return String.fromCharCode(parseInt('0x' + h1 + h2 + h3 + h4)); |
88 | 58 | } |
89 | 59 |
|
90 | | -digits |
91 | | - = ds:[0-9]+ { |
92 | | - //the number might start with 0 but must not be interpreted as an octal number |
93 | | - //Hence, the base is passed to parseInt explicitely |
94 | | - return parseInt((ds.join('')), 10); |
95 | | - } |
96 | | - |
97 | | -hexDigit |
98 | | - = [0-9a-fA-F] |
| 60 | +digits = $([0-9]+) |
99 | 61 |
|
100 | | -_ "whitespace" |
101 | | - = w:whitespace* { return w.join(''); } |
| 62 | +hexDigit = [0-9a-fA-F] |
102 | 63 |
|
103 | | -// Whitespace is undefined in the original JSON grammar, so I assume a simple |
104 | | -// conventional definition consistent with ECMA-262, 5th ed. |
105 | | -whitespace |
106 | | - = [ \t\n\r] |
| 64 | +_ = $([ \t\n\r]*) |
0 commit comments