diff --git a/spec/fluent.ebnf b/spec/fluent.ebnf index 48d755b..19a0c0a 100644 --- a/spec/fluent.ebnf +++ b/spec/fluent.ebnf @@ -22,7 +22,7 @@ CommentLine ::= ("###" | "##" | "#") ("\u0020" /.*/)? line_end junk_line ::= /.*/ line_end /* Attributes of Messages and Terms. */ -Attribute ::= line_end blank? "." Identifier blank_inline? "=" blank_inline? Pattern +Attribute ::= line_end blank? "." Name blank_inline? "=" blank_inline? Pattern /* Value types: Pattern and VariantList. */ Value ::= Pattern @@ -69,7 +69,7 @@ argument_list ::= (Argument blank? "," blank?)* Argument? Argument ::= NamedArgument | InlineExpression NamedArgument ::= Identifier blank? ":" blank? (StringLiteral | NumberLiteral) -AttributeExpression ::= (MessageReference | TermReference) "." Identifier +AttributeExpression ::= (MessageReference | TermReference) "." Name VariantExpression ::= TermReference VariantKey /* Block Expressions */ @@ -77,18 +77,15 @@ SelectExpression ::= InlineExpression blank? "->" blank_inline? variant_list variant_list ::= Variant* DefaultVariant Variant* line_end Variant ::= line_end blank? VariantKey blank_inline? Value DefaultVariant ::= line_end blank? "*" VariantKey blank_inline? Value -VariantKey ::= "[" blank? (NumberLiteral | VariantName) blank? "]" -VariantName ::= word (blank word)* +VariantKey ::= "[" blank? (NumberLiteral | Name) blank? "]" -/* Identifiers */ +/* Identifiers and Names */ Identifier ::= identifier +Name ::= identifier TermIdentifier ::= "-" identifier VariableIdentifier ::= "$" identifier Function ::= [A-Z] [A-Z_?-]* - -/* Tokens */ identifier ::= [a-zA-Z] [a-zA-Z0-9_-]* -word ::= (regular_char - backslash - "}" - "{" - "]" - "[" - "=")+ /* Characters */ backslash ::= "\\" diff --git a/syntax/ast.mjs b/syntax/ast.mjs index 6ec6fcc..4aa27e7 100644 --- a/syntax/ast.mjs +++ b/syntax/ast.mjs @@ -159,10 +159,10 @@ export class CallExpression extends Expression { } export class Attribute extends SyntaxNode { - constructor(id, value) { + constructor(name, value) { super(); this.type = "Attribute"; - this.id = id; + this.name = name; this.value = value; } } @@ -194,10 +194,11 @@ export class Identifier extends SyntaxNode { } } -export class VariantName extends Identifier { +export class Name extends SyntaxNode { constructor(name) { - super(name); - this.type = "VariantName"; + super(); + this.type = "Name"; + this.name = name; } } diff --git a/syntax/grammar.mjs b/syntax/grammar.mjs index 547abc8..a220264 100644 --- a/syntax/grammar.mjs +++ b/syntax/grammar.mjs @@ -99,7 +99,7 @@ let Attribute = defer(() => line_end, maybe(blank), string("."), - Identifier.abstract, + Name.abstract, maybe(blank_inline), string("="), maybe(blank_inline), @@ -275,7 +275,7 @@ let AttributeExpression = defer(() => MessageReference, TermReference).abstract, string("."), - Identifier.abstract) + Name.abstract) .map(keep_abstract) .chain(list_into(FTL.AttributeExpression))); @@ -335,28 +335,20 @@ let VariantKey = defer(() => maybe(blank), either( NumberLiteral, - VariantName), + Name), maybe(blank), string("]")) .map(element_at(2))); -let VariantName = defer(() => - sequence( - word, - repeat( - sequence( - blank, - word))) - .map(flatten(2)) - .map(join) - .chain(into(FTL.VariantName))); - -/* ----------- */ -/* Identifiers */ +/* --------------------- */ +/* Identifiers and Names */ let Identifier = defer(() => identifier.chain(into(FTL.Identifier))); +let Name = defer(() => + identifier.chain(into(FTL.Name))); + let TermIdentifier = defer(() => sequence( string("-"), @@ -380,8 +372,6 @@ let Function = .map(join) .chain(into(FTL.Function)); -/* ------ */ -/* Tokens */ let identifier = sequence( charset("a-zA-Z"), @@ -390,18 +380,6 @@ let identifier = .map(flatten(1)) .map(join); -let word = defer(() => - repeat1( - and( - not(string("=")), - not(string("[")), - not(string("]")), - not(string("{")), - not(string("}")), - not(backslash), - regular_char)) - .map(join)); - /* ---------- */ /* Characters */ diff --git a/test/fixtures/leading_dots.json b/test/fixtures/leading_dots.json index 962a3e5..148334d 100644 --- a/test/fixtures/leading_dots.json +++ b/test/fixtures/leading_dots.json @@ -199,8 +199,8 @@ "attributes": [ { "type": "Attribute", - "id": { - "type": "Identifier", + "name": { + "type": "Name", "name": "Value" }, "value": { @@ -251,8 +251,8 @@ "attributes": [ { "type": "Attribute", - "id": { - "type": "Identifier", + "name": { + "type": "Name", "name": "accesskey" }, "value": { @@ -278,8 +278,8 @@ "attributes": [ { "type": "Attribute", - "id": { - "type": "Identifier", + "name": { + "type": "Name", "name": "attribute" }, "value": { @@ -305,8 +305,8 @@ "attributes": [ { "type": "Attribute", - "id": { - "type": "Identifier", + "name": { + "type": "Name", "name": "attribute" }, "value": { @@ -350,7 +350,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "one" }, "value": { @@ -367,7 +367,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "other" }, "value": { @@ -433,8 +433,8 @@ "attributes": [ { "type": "Attribute", - "id": { - "type": "Identifier", + "name": { + "type": "Name", "name": "attribute" }, "value": { diff --git a/test/fixtures/member_expressions.json b/test/fixtures/member_expressions.json index f23f28a..fa14ccf 100644 --- a/test/fixtures/member_expressions.json +++ b/test/fixtures/member_expressions.json @@ -22,7 +22,7 @@ } }, "key": { - "type": "VariantName", + "type": "Name", "name": "case" } } @@ -53,7 +53,7 @@ } }, "name": { - "type": "Identifier", + "type": "Name", "name": "attr" } } diff --git a/test/fixtures/messages.json b/test/fixtures/messages.json index 1a5b5c4..6b19b22 100644 --- a/test/fixtures/messages.json +++ b/test/fixtures/messages.json @@ -37,8 +37,8 @@ "attributes": [ { "type": "Attribute", - "id": { - "type": "Identifier", + "name": { + "type": "Name", "name": "attr" }, "value": { @@ -72,8 +72,8 @@ "attributes": [ { "type": "Attribute", - "id": { - "type": "Identifier", + "name": { + "type": "Name", "name": "attr1" }, "value": { @@ -88,8 +88,8 @@ }, { "type": "Attribute", - "id": { - "type": "Identifier", + "name": { + "type": "Name", "name": "attr2" }, "value": { @@ -115,8 +115,8 @@ "attributes": [ { "type": "Attribute", - "id": { - "type": "Identifier", + "name": { + "type": "Name", "name": "attr" }, "value": { @@ -142,8 +142,8 @@ "attributes": [ { "type": "Attribute", - "id": { - "type": "Identifier", + "name": { + "type": "Name", "name": "attr1" }, "value": { @@ -158,8 +158,8 @@ }, { "type": "Attribute", - "id": { - "type": "Identifier", + "name": { + "type": "Name", "name": "attr2" }, "value": { @@ -185,8 +185,8 @@ "attributes": [ { "type": "Attribute", - "id": { - "type": "Identifier", + "name": { + "type": "Name", "name": "attr1" }, "value": { diff --git a/test/fixtures/mixed_entries.json b/test/fixtures/mixed_entries.json index 4e349a5..27f8fae 100644 --- a/test/fixtures/mixed_entries.json +++ b/test/fixtures/mixed_entries.json @@ -41,8 +41,8 @@ "attributes": [ { "type": "Attribute", - "id": { - "type": "Identifier", + "name": { + "type": "Name", "name": "attr" }, "value": { diff --git a/test/fixtures/multiline_values.json b/test/fixtures/multiline_values.json index 645a09b..2b06d1a 100644 --- a/test/fixtures/multiline_values.json +++ b/test/fixtures/multiline_values.json @@ -47,8 +47,8 @@ "attributes": [ { "type": "Attribute", - "id": { - "type": "Identifier", + "name": { + "type": "Name", "name": "attr" }, "value": { @@ -74,8 +74,8 @@ "attributes": [ { "type": "Attribute", - "id": { - "type": "Identifier", + "name": { + "type": "Name", "name": "attr" }, "value": { diff --git a/test/fixtures/select_expressions.ftl b/test/fixtures/select_expressions.ftl index e1c420a..3c54f57 100644 --- a/test/fixtures/select_expressions.ftl +++ b/test/fixtures/select_expressions.ftl @@ -6,7 +6,7 @@ new-messages = valid-selector = { -term.case -> - *[ many words ] value + *[key] value } # ERROR diff --git a/test/fixtures/select_expressions.json b/test/fixtures/select_expressions.json index d13fba6..07a107d 100644 --- a/test/fixtures/select_expressions.json +++ b/test/fixtures/select_expressions.json @@ -44,7 +44,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "other" }, "value": { @@ -96,7 +96,7 @@ } }, "name": { - "type": "Identifier", + "type": "Name", "name": "case" } }, @@ -104,8 +104,8 @@ { "type": "Variant", "key": { - "type": "VariantName", - "name": "many words" + "type": "Name", + "name": "key" }, "value": { "type": "Pattern", @@ -156,7 +156,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "one" }, "value": { @@ -202,7 +202,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "one" }, "value": { @@ -220,7 +220,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "two" }, "value": { diff --git a/test/fixtures/select_indent.json b/test/fixtures/select_indent.json index e9acf13..d0a003f 100644 --- a/test/fixtures/select_indent.json +++ b/test/fixtures/select_indent.json @@ -25,7 +25,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "key" }, "value": { @@ -71,7 +71,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "key" }, "value": { @@ -117,7 +117,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "key" }, "value": { @@ -163,7 +163,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "key" }, "value": { @@ -209,7 +209,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "key" }, "value": { @@ -255,7 +255,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "key" }, "value": { @@ -301,7 +301,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "key" }, "value": { @@ -347,7 +347,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "key" }, "value": { @@ -393,7 +393,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "key" }, "value": { @@ -439,7 +439,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "key" }, "value": { @@ -456,7 +456,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "other" }, "value": { @@ -502,7 +502,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "key" }, "value": { @@ -519,7 +519,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "other" }, "value": { @@ -574,7 +574,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "key" }, "value": { @@ -591,7 +591,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "other" }, "value": { @@ -637,7 +637,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "key" }, "value": { @@ -654,7 +654,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "other" }, "value": { diff --git a/test/fixtures/sparse_entries.json b/test/fixtures/sparse_entries.json index 549263b..5af5800 100644 --- a/test/fixtures/sparse_entries.json +++ b/test/fixtures/sparse_entries.json @@ -29,8 +29,8 @@ "attributes": [ { "type": "Attribute", - "id": { - "type": "Identifier", + "name": { + "type": "Name", "name": "attr" }, "value": { @@ -64,8 +64,8 @@ "attributes": [ { "type": "Attribute", - "id": { - "type": "Identifier", + "name": { + "type": "Name", "name": "attr" }, "value": { @@ -120,7 +120,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "one" }, "value": { @@ -137,7 +137,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "two" }, "value": { diff --git a/test/fixtures/terms.json b/test/fixtures/terms.json index 790e607..4e959dc 100644 --- a/test/fixtures/terms.json +++ b/test/fixtures/terms.json @@ -19,8 +19,8 @@ "attributes": [ { "type": "Attribute", - "id": { - "type": "Identifier", + "name": { + "type": "Name", "name": "attr" }, "value": { diff --git a/test/fixtures/variant_keys.ftl b/test/fixtures/variant_keys.ftl new file mode 100644 index 0000000..7586d52 --- /dev/null +++ b/test/fixtures/variant_keys.ftl @@ -0,0 +1,37 @@ +-simple-identifier = + { + *[key] value + } + +-identifier-surrounded-by-whitespace = + { + *[ key ] value + } + +-int-number = + { + *[1] value + } + +-float-number = + { + *[3.14] value + } + +# ERROR +-invalid-identifier = + { + *[two words] value + } + +# ERROR +-invalid-int = + { + *[1 apple] value + } + +# ERROR +-invalid-int = + { + *[3.14 apples] value + } diff --git a/test/fixtures/variant_keys.json b/test/fixtures/variant_keys.json new file mode 100644 index 0000000..8588a80 --- /dev/null +++ b/test/fixtures/variant_keys.json @@ -0,0 +1,156 @@ +{ + "type": "Resource", + "body": [ + { + "type": "Term", + "id": { + "type": "Identifier", + "name": "-simple-identifier" + }, + "value": { + "type": "VariantList", + "variants": [ + { + "type": "Variant", + "key": { + "type": "Name", + "name": "key" + }, + "value": { + "type": "Pattern", + "elements": [ + { + "type": "TextElement", + "value": "value" + } + ] + }, + "default": true + } + ] + }, + "attributes": [], + "comment": null + }, + { + "type": "Term", + "id": { + "type": "Identifier", + "name": "-identifier-surrounded-by-whitespace" + }, + "value": { + "type": "VariantList", + "variants": [ + { + "type": "Variant", + "key": { + "type": "Name", + "name": "key" + }, + "value": { + "type": "Pattern", + "elements": [ + { + "type": "TextElement", + "value": "value" + } + ] + }, + "default": true + } + ] + }, + "attributes": [], + "comment": null + }, + { + "type": "Term", + "id": { + "type": "Identifier", + "name": "-int-number" + }, + "value": { + "type": "VariantList", + "variants": [ + { + "type": "Variant", + "key": { + "type": "NumberLiteral", + "value": "1" + }, + "value": { + "type": "Pattern", + "elements": [ + { + "type": "TextElement", + "value": "value" + } + ] + }, + "default": true + } + ] + }, + "attributes": [], + "comment": null + }, + { + "type": "Term", + "id": { + "type": "Identifier", + "name": "-float-number" + }, + "value": { + "type": "VariantList", + "variants": [ + { + "type": "Variant", + "key": { + "type": "NumberLiteral", + "value": "3.14" + }, + "value": { + "type": "Pattern", + "elements": [ + { + "type": "TextElement", + "value": "value" + } + ] + }, + "default": true + } + ] + }, + "attributes": [], + "comment": null + }, + { + "type": "Comment", + "content": "ERROR" + }, + { + "type": "Junk", + "annotations": [], + "content": "-invalid-identifier =\n {\n *[two words] value\n }\n" + }, + { + "type": "Comment", + "content": "ERROR" + }, + { + "type": "Junk", + "annotations": [], + "content": "-invalid-int =\n {\n *[1 apple] value\n }\n" + }, + { + "type": "Comment", + "content": "ERROR" + }, + { + "type": "Junk", + "annotations": [], + "content": "-invalid-int =\n {\n *[3.14 apples] value\n }\n" + } + ] +} diff --git a/test/fixtures/variant_lists.json b/test/fixtures/variant_lists.json index 38f08db..536e4a7 100644 --- a/test/fixtures/variant_lists.json +++ b/test/fixtures/variant_lists.json @@ -13,7 +13,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "key" }, "value": { @@ -105,7 +105,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "one" }, "value": { @@ -114,7 +114,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "two" }, "value": { @@ -149,7 +149,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "one" }, "value": { @@ -167,7 +167,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "two" }, "value": { diff --git a/test/fixtures/variants_indent.json b/test/fixtures/variants_indent.json index 6171029..be9c73d 100644 --- a/test/fixtures/variants_indent.json +++ b/test/fixtures/variants_indent.json @@ -13,7 +13,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "key" }, "value": { @@ -44,7 +44,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "key" }, "value": { @@ -75,7 +75,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "key" }, "value": { @@ -106,7 +106,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "key" }, "value": { @@ -123,7 +123,7 @@ { "type": "Variant", "key": { - "type": "VariantName", + "type": "Name", "name": "other" }, "value": {