Skip to content

Commit d6a3a25

Browse files
committed
Add Parameterized Terms
1 parent bf46e18 commit d6a3a25

11 files changed

+513
-81
lines changed

spec/fluent.ebnf

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,10 @@ NumberLiteral ::= "-"? digit+ ("." digit+)?
6464
MessageReference ::= Identifier
6565
TermReference ::= "-" Identifier
6666
VariableReference ::= "$" Identifier
67-
CallExpression ::= Function blank? "(" blank? argument_list blank? ")"
67+
FunctionReference ::= Identifier
68+
CallExpression ::= Callee blank? "(" blank? argument_list blank? ")"
69+
Callee ::= FunctionReference
70+
| TermReference
6871
argument_list ::= (Argument blank? "," blank?)* Argument?
6972
Argument ::= NamedArgument
7073
| InlineExpression
@@ -79,9 +82,8 @@ Variant ::= line_end blank? VariantKey blank_inline? Value
7982
DefaultVariant ::= line_end blank? "*" VariantKey blank_inline? Value
8083
VariantKey ::= "[" blank? (NumberLiteral | Identifier) blank? "]"
8184

82-
/* Identifiers */
85+
/* Identifier */
8386
Identifier ::= [a-zA-Z] [a-zA-Z0-9_-]*
84-
Function ::= [A-Z] [A-Z_?-]*
8587

8688
/* Content Characters
8789
*

spec/valid.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,6 @@ Invalid Select Expressions:
5454

5555
SelectExpression.selector > MessageReference
5656
SelectExpression.selector > TermReference
57+
SelectExpression.selector > CallExpression.callee > TermReference
5758
SelectExpression.selector > VariantExpression
5859
SelectExpression.selector > AttributeExpression.ref > MessageReference

syntax/abstract.mjs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,13 @@ export function list_into(Type) {
6868
let invalid_selector_found =
6969
selector instanceof FTL.MessageReference
7070
|| selector instanceof FTL.TermReference
71+
|| (selector instanceof FTL.CallExpression
72+
&& selector.callee instanceof FTL.TermReference)
7173
|| selector instanceof FTL.VariantExpression
7274
|| (selector instanceof FTL.AttributeExpression
7375
&& selector.ref instanceof FTL.MessageReference);
7476
if (invalid_selector_found) {
75-
return never("Invalid selector type: ${selector.type}.");
77+
return never(`Invalid selector type: ${selector.type}.`);
7678
}
7779
let invalid_variants_found = variants.some(
7880
variant => variant.value instanceof FTL.VariantList);
@@ -94,14 +96,24 @@ export function list_into(Type) {
9496

9597
export function into(Type) {
9698
switch (Type) {
99+
case FTL.FunctionReference:
100+
const VALID_FUNCTION_NAME = /^[A-Z][A-Z0-9_?-]*$/;
101+
return identifier => {
102+
if (!VALID_FUNCTION_NAME.test(identifier.name)) {
103+
return never(
104+
`Invalid function name: ${identifier.name}. ` +
105+
"Function names must be upper-case.");
106+
}
107+
return always(new Type(identifier));
108+
};
97109
case FTL.Placeable:
98110
return expression => {
99111
let invalid_expression_found =
100112
expression instanceof FTL.AttributeExpression
101113
&& expression.ref instanceof FTL.TermReference;
102114
if (invalid_expression_found) {
103115
return never(
104-
"Invalid expression type: ${expression.type}.");
116+
`Invalid expression type: ${expression.type}.`);
105117
}
106118
return always(new Type(expression));
107119
};

syntax/ast.mjs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,14 @@ export class VariableReference extends Expression {
121121
}
122122
}
123123

124+
export class FunctionReference extends Expression {
125+
constructor(id) {
126+
super();
127+
this.type = "FunctionReference";
128+
this.id = id;
129+
}
130+
}
131+
124132
export class SelectExpression extends Expression {
125133
constructor(selector, variants) {
126134
super();
@@ -222,13 +230,6 @@ export class ResourceComment extends BaseComment {
222230
}
223231
}
224232

225-
export class Function extends Identifier {
226-
constructor(name) {
227-
super(name);
228-
this.type = "Function";
229-
}
230-
}
231-
232233
export class Junk extends SyntaxNode {
233234
constructor(content) {
234235
super();

syntax/grammar.mjs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,12 @@ let VariableReference = defer(() =>
239239
.map(element_at(1))
240240
.chain(into(FTL.VariableReference)));
241241

242+
let FunctionReference = defer(() =>
243+
Identifier.chain(into(FTL.FunctionReference)));
244+
242245
let CallExpression = defer(() =>
243246
sequence(
244-
Function.abstract,
247+
Callee.abstract,
245248
maybe(blank),
246249
string("("),
247250
maybe(blank),
@@ -251,6 +254,11 @@ let CallExpression = defer(() =>
251254
.map(keep_abstract)
252255
.chain(list_into(FTL.CallExpression)));
253256

257+
let Callee =
258+
either(
259+
FunctionReference,
260+
TermReference);
261+
254262
let argument_list = defer(() =>
255263
sequence(
256264
repeat(
@@ -352,7 +360,7 @@ let VariantKey = defer(() =>
352360
.map(element_at(2)));
353361

354362
/* ----------- */
355-
/* Identifiers */
363+
/* Identifier */
356364

357365
let Identifier =
358366
sequence(
@@ -363,15 +371,6 @@ let Identifier =
363371
.map(join)
364372
.chain(into(FTL.Identifier));
365373

366-
let Function =
367-
sequence(
368-
charset("A-Z"),
369-
repeat(
370-
charset("A-Z_?-")))
371-
.map(flatten(1))
372-
.map(join)
373-
.chain(into(FTL.Function));
374-
375374
/* -------------------------------------------------------------------------- */
376375
/* Content Characters
377376
*

test/fixtures/call_expressions.ftl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
## Callees
2+
3+
function-callee = {FUNCTION()}
4+
term-callee = {-term()}
5+
6+
# ERROR MessageReference is not a valid callee.
7+
message-callee = {message()}
8+
# ERROR VariableReference is not a valid callee.
9+
variable-callee = {$variable()}
10+
11+
## Arguments
12+
113
positional-args = {FUN(1, "a", msg)}
214
named-args = {FUN(x: 1, y: "Y")}
315
dense-named-args = {FUN(x:1, y:"Y")}

0 commit comments

Comments
 (0)