Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions fluent.runtime/tests/format/test_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ def my_function(arg, kwarg1=None, kwarg2="default"):
pass-kwarg1 = { MYFUNC("a", kwarg1: 1) }
pass-kwarg2 = { MYFUNC("a", kwarg2: "other") }
pass-kwargs = { MYFUNC("a", kwarg1: 1, kwarg2: "other") }
pass-user-kwarg = { MYFUNC("a", kwarg1: $foo) }
pass-user-arg = { MYFUNC($arg) }
"""
)
Expand Down Expand Up @@ -170,6 +171,20 @@ def test_pass_kwargs(self, args_passed, bundle):
assert args_passed == [("a", 1, "other")]
assert len(errs) == 0

def test_pass_user_kwarg(self, args_passed, bundle):
val, errs = bundle.format_pattern(
bundle.get_message("pass-user-kwarg").value, {"foo": 42}
)
assert args_passed == [("a", 42, "default")]
assert len(errs) == 0

def test_missing_kwarg(self, args_passed, bundle):
val, errs = bundle.format_pattern(
bundle.get_message("pass-user-kwarg").value, {}
)
assert args_passed == [("a", FluentNone("foo"), "default")]
assert len(errs) == 1

def test_missing_arg(self, args_passed, bundle):
val, errs = bundle.format_pattern(bundle.get_message("pass-user-arg").value, {})
assert args_passed == [(FluentNone("arg"), None, "default")]
Expand Down
8 changes: 8 additions & 0 deletions fluent.runtime/tests/format/test_parameterized_terms.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def bundle(self):
thing-with-arg = { -thing(article: "indefinite") }
thing-positional-arg = { -thing("foo") }
thing-fallback = { -thing(article: "somethingelse") }
thing-variable-arg = { -thing(article: $art) }
bad-term = { -missing() }
"""
)
Expand Down Expand Up @@ -65,6 +66,13 @@ def test_fallback(self, bundle):
assert val == "the thing"
assert errs == []

def test_variable_named_arg(self, bundle):
val, errs = bundle.format_pattern(
bundle.get_message("thing-variable-arg").value, {"art": "indefinite"}
)
assert val == "a thing"
assert errs == []

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe also add a test that checks for no args like for test_functions.py?

    def test_missing_variable_named_arg(self, bundle):
        val, errs = bundle.format_pattern(
            bundle.get_message("thing-variable-arg").value, {}
        )
        assert val == "the thing"
        assert errs == [FluentReferenceError('Unknown external: art')]

def test_no_implicit_access_to_external_args(self, bundle):
# The '-thing' term should not get passed article="indefinite"
val, errs = bundle.format_pattern(
Expand Down
2 changes: 1 addition & 1 deletion fluent.syntax/fluent/syntax/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ class NamedArgument(SyntaxNode):
def __init__(
self,
name: "Identifier",
value: Union[NumberLiteral, StringLiteral],
value: Union[NumberLiteral, StringLiteral, VariableReference],
**kwargs: Any
):
super().__init__(**kwargs)
Expand Down
2 changes: 1 addition & 1 deletion fluent.syntax/fluent/syntax/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def get_error_message(code: str, args: tuple[Union[str, None], ...]) -> str:
if code == "E0013":
return "Expected variant key"
if code == "E0014":
return "Expected literal"
return "Expected literal or variable reference"
if code == "E0015":
return "Only one variant can be marked as default (*)"
if code == "E0016":
Expand Down
10 changes: 7 additions & 3 deletions fluent.syntax/fluent/syntax/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@ def get_call_argument(
ps.next()
ps.skip_blank()

value = self.get_literal(ps)
value = self.get_named_argument_value(ps)
return ast.NamedArgument(exp.id, value)

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

@with_span
def get_literal(
def get_named_argument_value(
self, ps: FluentParserStream
) -> Union[ast.NumberLiteral, ast.StringLiteral]:
) -> Union[ast.NumberLiteral, ast.StringLiteral, ast.VariableReference]:
if ps.is_number_start():
return self.get_number(ps)
if ps.current_char == '"':
return self.get_string(ps)
if ps.current_char == "$":
ps.next()
id = self.get_identifier(ps)
return ast.VariableReference(id)
raise ParseError("E0014")
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ positional-args = {FUN(1, "a", msg)}
named-args = {FUN(x: 1, y: "Y")}
dense-named-args = {FUN(x:1, y:"Y")}
mixed-args = {FUN(1, "a", msg, x: 1, y: "Y")}
variable-args = {FUN($foo, arg: $bar)}

# ERROR Positional arg must not follow keyword args
shuffled-args = {FUN(1, x: 1, "a", y: "Y", msg)}
Expand Down Expand Up @@ -80,11 +81,11 @@ unindented-closing-paren = {FUN(
one-argument = {FUN(1,)}
many-arguments = {FUN(1, 2, 3,)}
inline-sparse-args = {FUN( 1, 2, 3, )}
mulitline-args = {FUN(
multiline-args = {FUN(
1,
2,
)}
mulitline-sparse-args = {FUN(
multiline-sparse-args = {FUN(

1
,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,58 @@
"attributes": [],
"comment": null
},
{
"type": "Message",
"id": {
"type": "Identifier",
"name": "variable-args"
},
"value": {
"type": "Pattern",
"elements": [
{
"type": "Placeable",
"expression": {
"type": "FunctionReference",
"id": {
"type": "Identifier",
"name": "FUN"
},
"arguments": {
"type": "CallArguments",
"positional": [
{
"type": "VariableReference",
"id": {
"type": "Identifier",
"name": "foo"
}
}
],
"named": [
{
"type": "NamedArgument",
"name": {
"type": "Identifier",
"name": "arg"
},
"value": {
"type": "VariableReference",
"id": {
"type": "Identifier",
"name": "bar"
}
}
}
]
}
}
}
]
},
"attributes": [],
"comment": null
},
{
"type": "Comment",
"content": "ERROR Positional arg must not follow keyword args"
Expand Down Expand Up @@ -1022,7 +1074,7 @@
"type": "Message",
"id": {
"type": "Identifier",
"name": "mulitline-args"
"name": "multiline-args"
},
"value": {
"type": "Pattern",
Expand Down Expand Up @@ -1060,7 +1112,7 @@
"type": "Message",
"id": {
"type": "Identifier",
"name": "mulitline-sparse-args"
"name": "multiline-sparse-args"
},
"value": {
"type": "Pattern",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ key01 = { -term }
key02 = { -term () }
key03 = { -term(arg: 1) }
key04 = { -term("positional", narg1: 1, narg2: 2) }
key05 = { -term(arg: $foo) }
45 changes: 45 additions & 0 deletions fluent.syntax/tests/syntax/fixtures_reference/term_parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,51 @@
},
"attributes": [],
"comment": null
},
{
"type": "Message",
"id": {
"type": "Identifier",
"name": "key05"
},
"value": {
"type": "Pattern",
"elements": [
{
"type": "Placeable",
"expression": {
"type": "TermReference",
"id": {
"type": "Identifier",
"name": "term"
},
"attribute": null,
"arguments": {
"type": "CallArguments",
"positional": [],
"named": [
{
"type": "NamedArgument",
"name": {
"type": "Identifier",
"name": "arg"
},
"value": {
"type": "VariableReference",
"id": {
"type": "Identifier",
"name": "foo"
}
}
}
]
}
}
}
]
},
"attributes": [],
"comment": null
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
"type": "Annotation",
"code": "E0014",
"arguments": [],
"message": "Expected literal",
"message": "Expected literal or variable reference",
"span": {
"type": "Span",
"start": 80,
Expand Down
Loading