Skip to content

Commit f088744

Browse files
committed
Allow VariableReference as NamedArgument value
1 parent e42ee44 commit f088744

10 files changed

Lines changed: 136 additions & 10 deletions

File tree

fluent.runtime/tests/format/test_functions.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ def my_function(arg, kwarg1=None, kwarg2="default"):
143143
pass-kwarg1 = { MYFUNC("a", kwarg1: 1) }
144144
pass-kwarg2 = { MYFUNC("a", kwarg2: "other") }
145145
pass-kwargs = { MYFUNC("a", kwarg1: 1, kwarg2: "other") }
146+
pass-user-kwarg = { MYFUNC("a", kwarg1: $foo) }
146147
pass-user-arg = { MYFUNC($arg) }
147148
"""
148149
)
@@ -170,6 +171,20 @@ def test_pass_kwargs(self, args_passed, bundle):
170171
assert args_passed == [("a", 1, "other")]
171172
assert len(errs) == 0
172173

174+
def test_pass_user_kwarg(self, args_passed, bundle):
175+
val, errs = bundle.format_pattern(
176+
bundle.get_message("pass-user-kwarg").value, {"foo": 42}
177+
)
178+
assert args_passed == [("a", 42, "default")]
179+
assert len(errs) == 0
180+
181+
def test_missing_kwarg(self, args_passed, bundle):
182+
val, errs = bundle.format_pattern(
183+
bundle.get_message("pass-user-kwarg").value, {}
184+
)
185+
assert args_passed == [("a", FluentNone("foo"), "default")]
186+
assert len(errs) == 1
187+
173188
def test_missing_arg(self, args_passed, bundle):
174189
val, errs = bundle.format_pattern(bundle.get_message("pass-user-arg").value, {})
175190
assert args_passed == [(FluentNone("arg"), None, "default")]

fluent.runtime/tests/format/test_parameterized_terms.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def bundle(self):
2323
thing-with-arg = { -thing(article: "indefinite") }
2424
thing-positional-arg = { -thing("foo") }
2525
thing-fallback = { -thing(article: "somethingelse") }
26+
thing-variable-arg = { -thing(article: $art) }
2627
bad-term = { -missing() }
2728
"""
2829
)
@@ -65,6 +66,13 @@ def test_fallback(self, bundle):
6566
assert val == "the thing"
6667
assert errs == []
6768

69+
def test_variable_named_arg(self, bundle):
70+
val, errs = bundle.format_pattern(
71+
bundle.get_message("thing-variable-arg").value, {"art": "indefinite"}
72+
)
73+
assert val == "a thing"
74+
assert errs == []
75+
6876
def test_no_implicit_access_to_external_args(self, bundle):
6977
# The '-thing' term should not get passed article="indefinite"
7078
val, errs = bundle.format_pattern(

fluent.syntax/fluent/syntax/ast.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ class NamedArgument(SyntaxNode):
327327
def __init__(
328328
self,
329329
name: "Identifier",
330-
value: Union[NumberLiteral, StringLiteral],
330+
value: Union[NumberLiteral, StringLiteral, VariableReference],
331331
**kwargs: Any
332332
):
333333
super().__init__(**kwargs)

fluent.syntax/fluent/syntax/errors.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def get_error_message(code: str, args: tuple[Union[str, None], ...]) -> str:
3838
if code == "E0013":
3939
return "Expected variant key"
4040
if code == "E0014":
41-
return "Expected literal"
41+
return "Expected literal or variable reference"
4242
if code == "E0015":
4343
return "Only one variant can be marked as default (*)"
4444
if code == "E0016":

fluent.syntax/fluent/syntax/parser.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ def get_call_argument(
653653
ps.next()
654654
ps.skip_blank()
655655

656-
value = self.get_literal(ps)
656+
value = self.get_named_argument_value(ps)
657657
return ast.NamedArgument(exp.id, value)
658658

659659
raise ParseError("E0009")
@@ -717,11 +717,15 @@ def get_string(self, ps: FluentParserStream) -> ast.StringLiteral:
717717
return ast.StringLiteral(value)
718718

719719
@with_span
720-
def get_literal(
720+
def get_named_argument_value(
721721
self, ps: FluentParserStream
722-
) -> Union[ast.NumberLiteral, ast.StringLiteral]:
722+
) -> Union[ast.NumberLiteral, ast.StringLiteral, ast.VariableReference]:
723723
if ps.is_number_start():
724724
return self.get_number(ps)
725725
if ps.current_char == '"':
726726
return self.get_string(ps)
727+
if ps.current_char == "$":
728+
ps.next()
729+
id = self.get_identifier(ps)
730+
return ast.VariableReference(id)
727731
raise ParseError("E0014")

fluent.syntax/tests/syntax/fixtures_reference/call_expressions.ftl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ positional-args = {FUN(1, "a", msg)}
1919
named-args = {FUN(x: 1, y: "Y")}
2020
dense-named-args = {FUN(x:1, y:"Y")}
2121
mixed-args = {FUN(1, "a", msg, x: 1, y: "Y")}
22+
variable-args = {FUN($foo, arg: $bar)}
2223
2324
# ERROR Positional arg must not follow keyword args
2425
shuffled-args = {FUN(1, x: 1, "a", y: "Y", msg)}
@@ -80,11 +81,11 @@ unindented-closing-paren = {FUN(
8081
one-argument = {FUN(1,)}
8182
many-arguments = {FUN(1, 2, 3,)}
8283
inline-sparse-args = {FUN( 1, 2, 3, )}
83-
mulitline-args = {FUN(
84+
multiline-args = {FUN(
8485
1,
8586
2,
8687
)}
87-
mulitline-sparse-args = {FUN(
88+
multiline-sparse-args = {FUN(
8889
8990
1
9091
,

fluent.syntax/tests/syntax/fixtures_reference/call_expressions.json

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,58 @@
351351
"attributes": [],
352352
"comment": null
353353
},
354+
{
355+
"type": "Message",
356+
"id": {
357+
"type": "Identifier",
358+
"name": "variable-args"
359+
},
360+
"value": {
361+
"type": "Pattern",
362+
"elements": [
363+
{
364+
"type": "Placeable",
365+
"expression": {
366+
"type": "FunctionReference",
367+
"id": {
368+
"type": "Identifier",
369+
"name": "FUN"
370+
},
371+
"arguments": {
372+
"type": "CallArguments",
373+
"positional": [
374+
{
375+
"type": "VariableReference",
376+
"id": {
377+
"type": "Identifier",
378+
"name": "foo"
379+
}
380+
}
381+
],
382+
"named": [
383+
{
384+
"type": "NamedArgument",
385+
"name": {
386+
"type": "Identifier",
387+
"name": "arg"
388+
},
389+
"value": {
390+
"type": "VariableReference",
391+
"id": {
392+
"type": "Identifier",
393+
"name": "bar"
394+
}
395+
}
396+
}
397+
]
398+
}
399+
}
400+
}
401+
]
402+
},
403+
"attributes": [],
404+
"comment": null
405+
},
354406
{
355407
"type": "Comment",
356408
"content": "ERROR Positional arg must not follow keyword args"
@@ -1022,7 +1074,7 @@
10221074
"type": "Message",
10231075
"id": {
10241076
"type": "Identifier",
1025-
"name": "mulitline-args"
1077+
"name": "multiline-args"
10261078
},
10271079
"value": {
10281080
"type": "Pattern",
@@ -1060,7 +1112,7 @@
10601112
"type": "Message",
10611113
"id": {
10621114
"type": "Identifier",
1063-
"name": "mulitline-sparse-args"
1115+
"name": "multiline-sparse-args"
10641116
},
10651117
"value": {
10661118
"type": "Pattern",

fluent.syntax/tests/syntax/fixtures_reference/term_parameters.ftl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ key01 = { -term }
66
key02 = { -term () }
77
key03 = { -term(arg: 1) }
88
key04 = { -term("positional", narg1: 1, narg2: 2) }
9+
key05 = { -term(arg: $foo) }

fluent.syntax/tests/syntax/fixtures_reference/term_parameters.json

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,51 @@
202202
},
203203
"attributes": [],
204204
"comment": null
205+
},
206+
{
207+
"type": "Message",
208+
"id": {
209+
"type": "Identifier",
210+
"name": "key05"
211+
},
212+
"value": {
213+
"type": "Pattern",
214+
"elements": [
215+
{
216+
"type": "Placeable",
217+
"expression": {
218+
"type": "TermReference",
219+
"id": {
220+
"type": "Identifier",
221+
"name": "term"
222+
},
223+
"attribute": null,
224+
"arguments": {
225+
"type": "CallArguments",
226+
"positional": [],
227+
"named": [
228+
{
229+
"type": "NamedArgument",
230+
"name": {
231+
"type": "Identifier",
232+
"name": "arg"
233+
},
234+
"value": {
235+
"type": "VariableReference",
236+
"id": {
237+
"type": "Identifier",
238+
"name": "foo"
239+
}
240+
}
241+
}
242+
]
243+
}
244+
}
245+
}
246+
]
247+
},
248+
"attributes": [],
249+
"comment": null
205250
}
206251
]
207252
}

fluent.syntax/tests/syntax/fixtures_structure/call_expression_errors.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
"type": "Annotation",
5353
"code": "E0014",
5454
"arguments": [],
55-
"message": "Expected literal",
55+
"message": "Expected literal or variable reference",
5656
"span": {
5757
"type": "Span",
5858
"start": 80,

0 commit comments

Comments
 (0)