Skip to content

Commit 9b7849d

Browse files
committed
(fluent) Use references with extra data rather than member expressions
1 parent 758a0a2 commit 9b7849d

23 files changed

+862
-669
lines changed

fluent/src/resolver.js

Lines changed: 122 additions & 326 deletions
Large diffs are not rendered by default.

fluent/src/resource.js

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ import FluentError from "./error.js";
22

33
// This regex is used to iterate through the beginnings of messages and terms.
44
// With the /m flag, the ^ matches at the beginning of every line.
5-
const RE_MESSAGE_START = /^(-?[a-zA-Z][a-zA-Z0-9_-]*) *= */mg;
5+
const RE_MESSAGE_START = /^(-?[a-zA-Z][\w-]*) *= */mg;
66

77
// Both Attributes and Variants are parsed in while loops. These regexes are
88
// used to break out of them.
9-
const RE_ATTRIBUTE_START = /\.([a-zA-Z][a-zA-Z0-9_-]*) *= */y;
9+
const RE_ATTRIBUTE_START = /\.([a-zA-Z][\w-]*) *= */y;
1010
// [^] matches all characters, including newlines.
1111
// XXX Use /s (dotall) when it's widely supported.
1212
const RE_VARIANT_START = /\*?\[[^]*?] */y;
1313

14-
const RE_IDENTIFIER = /(-?[a-zA-Z][a-zA-Z0-9_-]*)/y;
1514
const RE_NUMBER_LITERAL = /(-?[0-9]+(\.[0-9]+)?)/y;
15+
const RE_REFERENCE = /([$-])?([a-zA-Z][\w-]*)(?:\.([a-zA-Z][\w-]*))?/y;
1616

1717
// A "run" is a sequence of text or string literal characters which don't
1818
// require any special handling. For TextElements such special characters are: {
@@ -40,7 +40,7 @@ const TOKEN_BRACE_OPEN = /{\s*/y;
4040
const TOKEN_BRACE_CLOSE = /\s*}/y;
4141
const TOKEN_BRACKET_OPEN = /\[\s*/y;
4242
const TOKEN_BRACKET_CLOSE = /\s*]/y;
43-
const TOKEN_PAREN_OPEN = /\(\s*/y;
43+
const TOKEN_PAREN_OPEN = /\s*\(\s*/y;
4444
const TOKEN_ARROW = /\s*->\s*/y;
4545
const TOKEN_COLON = /\s*:\s*/y;
4646
// Note the optional comma. As a deviation from the Fluent EBNF, the parser
@@ -134,15 +134,20 @@ export default class FluentResource extends Map {
134134
return false;
135135
}
136136

137-
// Execute a regex, advance the cursor, and return the capture group.
137+
// Execute a regex, advance the cursor, and return all capture groups.
138138
function match(re) {
139139
re.lastIndex = cursor;
140140
let result = re.exec(source);
141141
if (result === null) {
142142
throw new FluentError(`Expected ${re.toString()}`);
143143
}
144144
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];
146151
}
147152

148153
function parseMessage() {
@@ -163,7 +168,7 @@ export default class FluentResource extends Map {
163168
let attrs = {};
164169

165170
while (test(RE_ATTRIBUTE_START)) {
166-
let name = match(RE_ATTRIBUTE_START);
171+
let name = match1(RE_ATTRIBUTE_START);
167172
let value = parsePattern();
168173
if (value === null) {
169174
throw new FluentError("Expected attribute value");
@@ -177,7 +182,7 @@ export default class FluentResource extends Map {
177182
function parsePattern() {
178183
// First try to parse any simple text on the same line as the id.
179184
if (test(RE_TEXT_RUN)) {
180-
var first = match(RE_TEXT_RUN);
185+
var first = match1(RE_TEXT_RUN);
181186
}
182187

183188
// If there's a placeable on the first line, parse a complex pattern.
@@ -216,7 +221,7 @@ export default class FluentResource extends Map {
216221

217222
while (true) {
218223
if (test(RE_TEXT_RUN)) {
219-
elements.push(match(RE_TEXT_RUN));
224+
elements.push(match1(RE_TEXT_RUN));
220225
continue;
221226
}
222227

@@ -294,27 +299,20 @@ export default class FluentResource extends Map {
294299
return parsePlaceable();
295300
}
296301

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";
308305

309306
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()};
311309
}
312310

313311
if (consumeToken(TOKEN_PAREN_OPEN)) {
314-
return {type: "call", ref, args: parseArguments()};
312+
return {type, name, attr, args: parseArguments()};
315313
}
316314

317-
return ref;
315+
return {type, name, attr, args: null};
318316
}
319317

320318
return parseLiteral();
@@ -378,7 +376,7 @@ export default class FluentResource extends Map {
378376
consumeToken(TOKEN_BRACKET_OPEN, FluentError);
379377
let key = test(RE_NUMBER_LITERAL)
380378
? parseNumberLiteral()
381-
: match(RE_IDENTIFIER);
379+
: match(RE_REFERENCE)[2];
382380
consumeToken(TOKEN_BRACKET_CLOSE, FluentError);
383381
return key;
384382
}
@@ -396,14 +394,14 @@ export default class FluentResource extends Map {
396394
}
397395

398396
function parseNumberLiteral() {
399-
return {type: "num", value: match(RE_NUMBER_LITERAL)};
397+
return {type: "num", value: match1(RE_NUMBER_LITERAL)};
400398
}
401399

402400
function parseStringLiteral() {
403401
consumeChar("\"", FluentError);
404402
let value = "";
405403
while (true) {
406-
value += match(RE_STRING_RUN);
404+
value += match1(RE_STRING_RUN);
407405

408406
if (source[cursor] === "\\") {
409407
value += parseEscapeSequence();
@@ -422,7 +420,7 @@ export default class FluentResource extends Map {
422420
// Unescape known escape sequences.
423421
function parseEscapeSequence() {
424422
if (test(RE_UNICODE_ESCAPE)) {
425-
let sequence = match(RE_UNICODE_ESCAPE);
423+
let sequence = match1(RE_UNICODE_ESCAPE);
426424
let codepoint = parseInt(sequence, 16);
427425
return codepoint <= 0xD7FF || 0xE000 <= codepoint
428426
// It's a Unicode scalar value.
@@ -433,7 +431,7 @@ export default class FluentResource extends Map {
433431
}
434432

435433
if (test(RE_STRING_ESCAPE)) {
436-
return match(RE_STRING_ESCAPE);
434+
return match1(RE_STRING_ESCAPE);
437435
}
438436

439437
throw new FluentError("Unknown escape sequence");

0 commit comments

Comments
 (0)