Skip to content

Commit 4e6cfc1

Browse files
committed
Forbid nested VariantLists
1 parent b6535b0 commit 4e6cfc1

File tree

6 files changed

+36
-74
lines changed

6 files changed

+36
-74
lines changed

fluent-syntax/src/parser.js

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ export default class FluentParser {
227227
ps.skipBlankInline();
228228
ps.expectChar("=");
229229

230-
const value = this.maybeGetValue(ps, {allowVariantList: false});
230+
const value = this.maybeGetPattern(ps);
231231
const attrs = this.getAttributes(ps);
232232

233233
if (value === null && attrs.length === 0) {
@@ -244,11 +244,9 @@ export default class FluentParser {
244244
ps.skipBlankInline();
245245
ps.expectChar("=");
246246

247-
// XXX Once https://github.com/projectfluent/fluent/pull/220 lands,
248-
// getTerm will be the only place where VariantLists are still legal. Move
249-
// the code from getPatternOrVariantList up to here then, and remove the
250-
// allowVariantList switch.
251-
const value = this.maybeGetValue(ps, {allowVariantList: true});
247+
// Syntax 0.8 compat: VariantLists are supported but deprecated. They can
248+
// only be found as values of Terms. Nested VariantLists are not allowed.
249+
const value = this.maybeGetVariantList(ps) || this.maybeGetPattern(ps);
252250
if (value === null) {
253251
throw new ParseError("E0006", id.name);
254252
}
@@ -265,7 +263,7 @@ export default class FluentParser {
265263
ps.skipBlankInline();
266264
ps.expectChar("=");
267265

268-
const value = this.maybeGetValue(ps, {allowVariantList: false});
266+
const value = this.maybeGetPattern(ps);
269267
if (value === null) {
270268
throw new ParseError("E0012");
271269
}
@@ -312,7 +310,7 @@ export default class FluentParser {
312310
return this.getIdentifier(ps);
313311
}
314312

315-
getVariant(ps, {hasDefault, allowVariantList}) {
313+
getVariant(ps, {hasDefault}) {
316314
let defaultIndex = false;
317315

318316
if (ps.currentChar === "*") {
@@ -333,23 +331,21 @@ export default class FluentParser {
333331
ps.skipBlank();
334332
ps.expectChar("]");
335333

336-
// XXX We need to pass allowVariantList all the way down to here because
337-
// nested VariantLists in Terms are legal for now.
338-
const value = this.maybeGetValue(ps, {allowVariantList});
334+
const value = this.maybeGetPattern(ps);
339335
if (value === null) {
340336
throw new ParseError("E0012");
341337
}
342338

343339
return new AST.Variant(key, value, defaultIndex);
344340
}
345341

346-
getVariants(ps, {allowVariantList}) {
342+
getVariants(ps) {
347343
const variants = [];
348344
let hasDefault = false;
349345

350346
ps.skipBlank();
351347
while (ps.isVariantStart()) {
352-
const variant = this.getVariant(ps, {allowVariantList, hasDefault});
348+
const variant = this.getVariant(ps, {hasDefault});
353349

354350
if (variant.default) {
355351
hasDefault = true;
@@ -405,34 +401,34 @@ export default class FluentParser {
405401
return new AST.NumberLiteral(num);
406402
}
407403

408-
// maybeGetValue distinguishes between patterns which start on the same line
404+
// maybeGetPattern distinguishes between patterns which start on the same line
409405
// as the identifier (a.k.a. inline signleline patterns and inline multiline
410406
// patterns) and patterns which start on a new line (a.k.a. block multiline
411407
// patterns). The distinction is important for the dedentation logic: the
412408
// indent of the first line of a block pattern must be taken into account when
413409
// calculating the maximum common indent.
414-
maybeGetValue(ps, {allowVariantList}) {
410+
maybeGetPattern(ps) {
415411
ps.peekBlankInline();
416412
if (ps.isValueStart()) {
417413
ps.skipToPeek();
418-
return this.getPatternOrVariantList(
419-
ps, {isBlock: false, allowVariantList});
414+
return this.getPattern(ps, {isBlock: false});
420415
}
421416

422417
ps.peekBlankBlock();
423418
if (ps.isValueContinuation()) {
424419
ps.skipToPeek();
425-
return this.getPatternOrVariantList(
426-
ps, {isBlock: true, allowVariantList});
420+
return this.getPattern(ps, {isBlock: true});
427421
}
428422

429423
return null;
430424
}
431425

432-
// Parse a VariantList (if allowed) or a Pattern.
433-
getPatternOrVariantList(ps, {isBlock, allowVariantList}) {
434-
ps.peekBlankInline();
435-
if (allowVariantList && ps.currentPeek === "{") {
426+
// Deprecated in Syntax 0.8. VariantLists are only allowed as values of Terms.
427+
// Values of Messages, Attributes and Variants must be Patterns. This method
428+
// is only used in getTerm.
429+
maybeGetVariantList(ps) {
430+
ps.peekBlank();
431+
if (ps.currentPeek === "{") {
436432
const start = ps.peekOffset;
437433
ps.peek();
438434
ps.peekBlankInline();
@@ -441,19 +437,18 @@ export default class FluentParser {
441437
if (ps.isVariantStart()) {
442438
ps.resetPeek(start);
443439
ps.skipToPeek();
444-
return this.getVariantList(ps, {allowVariantList});
440+
return this.getVariantList(ps);
445441
}
446442
}
447443
}
448444

449445
ps.resetPeek();
450-
const pattern = this.getPattern(ps, {isBlock});
451-
return pattern;
446+
return null;
452447
}
453448

454449
getVariantList(ps) {
455450
ps.expectChar("{");
456-
var variants = this.getVariants(ps, {allowVariantList: true});
451+
var variants = this.getVariants(ps);
457452
ps.expectChar("}");
458453
return new AST.VariantList(variants);
459454
}
@@ -679,7 +674,7 @@ export default class FluentParser {
679674
ps.skipBlankInline();
680675
ps.expectLineEnd();
681676

682-
const variants = this.getVariants(ps, {allowVariantList: false});
677+
const variants = this.getVariants(ps);
683678
return new AST.SelectExpression(selector, variants);
684679
}
685680

fluent-syntax/test/fixtures_behavior/variant_lists.ftl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ message2 =
1717
*[one] One
1818
}
1919
20+
# ~ERROR E0014, pos 211
2021
-term2 =
2122
{
2223
*[one] {

fluent-syntax/test/fixtures_reference/select_expressions.ftl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ nested-select =
3939
}
4040
}
4141
42-
# ERROR VariantLists cannot appear in SelectExpressions
42+
# ERROR VariantLists cannot be Variant values.
4343
nested-variant-list =
4444
{ 1 ->
4545
*[one] {

fluent-syntax/test/fixtures_reference/select_expressions.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@
274274
},
275275
{
276276
"type": "Comment",
277-
"content": "ERROR VariantLists cannot appear in SelectExpressions"
277+
"content": "ERROR VariantLists cannot be Variant values."
278278
},
279279
{
280280
"type": "Junk",

fluent-syntax/test/fixtures_reference/variant_lists.ftl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ variant-list-in-message-attr = Value
2323
*[key] Value
2424
}
2525
26+
# ERROR VariantLists cannot be Variant values.
2627
-nested-variant-list-in-term =
2728
{
2829
*[one] {
@@ -37,7 +38,7 @@ variant-list-in-message-attr = Value
3738
}
3839
}
3940
40-
# ERROR VariantLists may not appear in SelectExpressions
41+
# ERROR VariantLists cannot be Variant values.
4142
nested-select-then-variant-list =
4243
{
4344
*[one] { 2 ->

fluent-syntax/test/fixtures_reference/variant_lists.json

Lines changed: 8 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -94,48 +94,13 @@
9494
"content": " .attr =\n {\n *[key] Value\n }\n\n"
9595
},
9696
{
97-
"type": "Term",
98-
"id": {
99-
"type": "Identifier",
100-
"name": "nested-variant-list-in-term"
101-
},
102-
"value": {
103-
"type": "VariantList",
104-
"variants": [
105-
{
106-
"type": "Variant",
107-
"key": {
108-
"type": "Identifier",
109-
"name": "one"
110-
},
111-
"value": {
112-
"type": "VariantList",
113-
"variants": [
114-
{
115-
"type": "Variant",
116-
"key": {
117-
"type": "Identifier",
118-
"name": "two"
119-
},
120-
"value": {
121-
"type": "Pattern",
122-
"elements": [
123-
{
124-
"type": "TextElement",
125-
"value": "Value"
126-
}
127-
]
128-
},
129-
"default": true
130-
}
131-
]
132-
},
133-
"default": true
134-
}
135-
]
136-
},
137-
"attributes": [],
138-
"comment": null
97+
"type": "Comment",
98+
"content": "ERROR VariantLists cannot be Variant values."
99+
},
100+
{
101+
"type": "Junk",
102+
"annotations": [],
103+
"content": "-nested-variant-list-in-term =\n {\n *[one] {\n *[two] Value\n }\n }\n\n"
139104
},
140105
{
141106
"type": "Term",
@@ -195,7 +160,7 @@
195160
},
196161
{
197162
"type": "Comment",
198-
"content": "ERROR VariantLists may not appear in SelectExpressions"
163+
"content": "ERROR VariantLists cannot be Variant values."
199164
},
200165
{
201166
"type": "Junk",

0 commit comments

Comments
 (0)