@@ -2,17 +2,17 @@ import FluentError from "./error.js";
2
2
3
3
// This regex is used to iterate through the beginnings of messages and terms.
4
4
// With the /m flag, the ^ matches at the beginning of every line.
5
- const RE_MESSAGE_START = / ^ ( - ? [ a - z A - Z ] [ a - z A - Z 0 - 9 _ - ] * ) * = * / mg;
5
+ const RE_MESSAGE_START = / ^ ( - ? [ a - z A - Z ] [ \w - ] * ) * = * / mg;
6
6
7
7
// Both Attributes and Variants are parsed in while loops. These regexes are
8
8
// used to break out of them.
9
- const RE_ATTRIBUTE_START = / \. ( [ a - z A - Z ] [ a - z A - Z 0 - 9 _ - ] * ) * = * / y;
9
+ const RE_ATTRIBUTE_START = / \. ( [ a - z A - Z ] [ \w - ] * ) * = * / y;
10
10
// [^] matches all characters, including newlines.
11
11
// XXX Use /s (dotall) when it's widely supported.
12
12
const RE_VARIANT_START = / \* ? \[ [ ^ ] * ?] * / y;
13
13
14
- const RE_IDENTIFIER = / ( - ? [ a - z A - Z ] [ a - z A - Z 0 - 9 _ - ] * ) / y;
15
14
const RE_NUMBER_LITERAL = / ( - ? [ 0 - 9 ] + ( \. [ 0 - 9 ] + ) ? ) / y;
15
+ const RE_REFERENCE = / ( [ $ - ] ) ? ( [ a - z A - Z ] [ \w - ] * ) (?: \. ( [ a - z A - Z ] [ \w - ] * ) ) ? / y;
16
16
17
17
// A "run" is a sequence of text or string literal characters which don't
18
18
// require any special handling. For TextElements such special characters are: {
@@ -40,7 +40,7 @@ const TOKEN_BRACE_OPEN = /{\s*/y;
40
40
const TOKEN_BRACE_CLOSE = / \s * } / y;
41
41
const TOKEN_BRACKET_OPEN = / \[ \s * / y;
42
42
const TOKEN_BRACKET_CLOSE = / \s * ] / y;
43
- const TOKEN_PAREN_OPEN = / \( \s * / y;
43
+ const TOKEN_PAREN_OPEN = / \s * \ (\s * / y;
44
44
const TOKEN_ARROW = / \s * - > \s * / y;
45
45
const TOKEN_COLON = / \s * : \s * / y;
46
46
// Note the optional comma. As a deviation from the Fluent EBNF, the parser
@@ -134,15 +134,20 @@ export default class FluentResource extends Map {
134
134
return false ;
135
135
}
136
136
137
- // Execute a regex, advance the cursor, and return the capture group .
137
+ // Execute a regex, advance the cursor, and return all capture groups .
138
138
function match ( re ) {
139
139
re . lastIndex = cursor ;
140
140
let result = re . exec ( source ) ;
141
141
if ( result === null ) {
142
142
throw new FluentError ( `Expected ${ re . toString ( ) } ` ) ;
143
143
}
144
144
cursor = re . lastIndex ;
145
- return result [ 1 ] ;
145
+ return result ;
146
+ }
147
+
148
+ // Execute a regex, advance the cursor, and return the capture group.
149
+ function match1 ( re ) {
150
+ return match ( re ) [ 1 ] ;
146
151
}
147
152
148
153
function parseMessage ( ) {
@@ -163,7 +168,7 @@ export default class FluentResource extends Map {
163
168
let attrs = { } ;
164
169
165
170
while ( test ( RE_ATTRIBUTE_START ) ) {
166
- let name = match ( RE_ATTRIBUTE_START ) ;
171
+ let name = match1 ( RE_ATTRIBUTE_START ) ;
167
172
let value = parsePattern ( ) ;
168
173
if ( value === null ) {
169
174
throw new FluentError ( "Expected attribute value" ) ;
@@ -177,7 +182,7 @@ export default class FluentResource extends Map {
177
182
function parsePattern ( ) {
178
183
// First try to parse any simple text on the same line as the id.
179
184
if ( test ( RE_TEXT_RUN ) ) {
180
- var first = match ( RE_TEXT_RUN ) ;
185
+ var first = match1 ( RE_TEXT_RUN ) ;
181
186
}
182
187
183
188
// If there's a placeable on the first line, parse a complex pattern.
@@ -216,7 +221,7 @@ export default class FluentResource extends Map {
216
221
217
222
while ( true ) {
218
223
if ( test ( RE_TEXT_RUN ) ) {
219
- elements . push ( match ( RE_TEXT_RUN ) ) ;
224
+ elements . push ( match1 ( RE_TEXT_RUN ) ) ;
220
225
continue ;
221
226
}
222
227
@@ -294,27 +299,20 @@ export default class FluentResource extends Map {
294
299
return parsePlaceable ( ) ;
295
300
}
296
301
297
- if ( consumeChar ( "$" ) ) {
298
- return { type : "var" , name : match ( RE_IDENTIFIER ) } ;
299
- }
300
-
301
- if ( test ( RE_IDENTIFIER ) ) {
302
- let ref = { type : "ref" , name : match ( RE_IDENTIFIER ) } ;
303
-
304
- if ( consumeChar ( "." ) ) {
305
- let name = match ( RE_IDENTIFIER ) ;
306
- return { type : "getattr" , ref, name} ;
307
- }
302
+ if ( test ( RE_REFERENCE ) ) {
303
+ let [ , sigil , name , attr = null ] = match ( RE_REFERENCE ) ;
304
+ let type = { "$" : "var" , "-" : "term" } [ sigil ] || "ref" ;
308
305
309
306
if ( source [ cursor ] === "[" ) {
310
- return { type : "getvar" , ref, selector : parseVariantKey ( ) } ;
307
+ // DEPRECATED VariantExpressions will be removed before 1.0.
308
+ return { type, name, selector : parseVariantKey ( ) } ;
311
309
}
312
310
313
311
if ( consumeToken ( TOKEN_PAREN_OPEN ) ) {
314
- return { type : "call" , ref , args : parseArguments ( ) } ;
312
+ return { type, name , attr , args : parseArguments ( ) } ;
315
313
}
316
314
317
- return ref ;
315
+ return { type , name , attr , args : null } ;
318
316
}
319
317
320
318
return parseLiteral ( ) ;
@@ -378,7 +376,7 @@ export default class FluentResource extends Map {
378
376
consumeToken ( TOKEN_BRACKET_OPEN , FluentError ) ;
379
377
let key = test ( RE_NUMBER_LITERAL )
380
378
? parseNumberLiteral ( )
381
- : match ( RE_IDENTIFIER ) ;
379
+ : match ( RE_REFERENCE ) [ 2 ] ;
382
380
consumeToken ( TOKEN_BRACKET_CLOSE , FluentError ) ;
383
381
return key ;
384
382
}
@@ -396,14 +394,14 @@ export default class FluentResource extends Map {
396
394
}
397
395
398
396
function parseNumberLiteral ( ) {
399
- return { type : "num" , value : match ( RE_NUMBER_LITERAL ) } ;
397
+ return { type : "num" , value : match1 ( RE_NUMBER_LITERAL ) } ;
400
398
}
401
399
402
400
function parseStringLiteral ( ) {
403
401
consumeChar ( "\"" , FluentError ) ;
404
402
let value = "" ;
405
403
while ( true ) {
406
- value += match ( RE_STRING_RUN ) ;
404
+ value += match1 ( RE_STRING_RUN ) ;
407
405
408
406
if ( source [ cursor ] === "\\" ) {
409
407
value += parseEscapeSequence ( ) ;
@@ -422,7 +420,7 @@ export default class FluentResource extends Map {
422
420
// Unescape known escape sequences.
423
421
function parseEscapeSequence ( ) {
424
422
if ( test ( RE_UNICODE_ESCAPE ) ) {
425
- let sequence = match ( RE_UNICODE_ESCAPE ) ;
423
+ let sequence = match1 ( RE_UNICODE_ESCAPE ) ;
426
424
let codepoint = parseInt ( sequence , 16 ) ;
427
425
return codepoint <= 0xD7FF || 0xE000 <= codepoint
428
426
// It's a Unicode scalar value.
@@ -433,7 +431,7 @@ export default class FluentResource extends Map {
433
431
}
434
432
435
433
if ( test ( RE_STRING_ESCAPE ) ) {
436
- return match ( RE_STRING_ESCAPE ) ;
434
+ return match1 ( RE_STRING_ESCAPE ) ;
437
435
}
438
436
439
437
throw new FluentError ( "Unknown escape sequence" ) ;
0 commit comments