2021-06-28 15:06:01 +02:00
|
|
|
import re
|
2022-06-08 11:26:10 +00:00
|
|
|
from typing import Dict
|
2020-10-23 20:13:22 +02:00
|
|
|
|
2021-06-28 15:06:01 +02:00
|
|
|
import librflxlang
|
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
|
|
from language.lexer import rflx_lexer
|
2022-06-08 11:26:10 +00:00
|
|
|
from tests.utils import parse, to_dict
|
2020-12-10 07:57:27 +01:00
|
|
|
|
2020-11-16 09:44:09 +01:00
|
|
|
|
|
|
|
|
def parse_buffer(
|
2021-10-08 10:09:55 +02:00
|
|
|
data: str, rule: str = librflxlang.GrammarRule.main_rule_rule
|
2020-12-24 23:14:47 +01:00
|
|
|
) -> librflxlang.AnalysisUnit:
|
|
|
|
|
ctx = librflxlang.AnalysisContext()
|
2020-11-16 09:44:09 +01:00
|
|
|
unit = ctx.get_from_buffer("text.rflx", data, rule=rule)
|
|
|
|
|
del ctx
|
|
|
|
|
return unit
|
2020-10-23 20:13:22 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_empty_file() -> None:
|
2020-11-16 09:44:09 +01:00
|
|
|
unit = parse_buffer("")
|
2020-10-23 20:13:22 +02:00
|
|
|
assert unit.root is None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_empty_package() -> None:
|
2020-11-16 09:44:09 +01:00
|
|
|
unit = parse_buffer(
|
2020-10-23 20:13:22 +02:00
|
|
|
"""
|
|
|
|
|
package Empty_Package is
|
|
|
|
|
end Empty_Package;
|
|
|
|
|
""",
|
|
|
|
|
)
|
2020-11-04 23:36:31 +01:00
|
|
|
assert to_dict(unit.root) == {
|
|
|
|
|
"context_clause": [],
|
2020-11-16 09:44:09 +01:00
|
|
|
"_kind": "Specification",
|
2020-11-04 23:36:31 +01:00
|
|
|
"package_declaration": {
|
|
|
|
|
"declarations": [],
|
2020-11-16 09:44:09 +01:00
|
|
|
"end_identifier": {"_kind": "UnqualifiedID", "_value": "Empty_Package"},
|
|
|
|
|
"identifier": {"_kind": "UnqualifiedID", "_value": "Empty_Package"},
|
2021-01-14 14:13:00 +01:00
|
|
|
"_kind": "PackageNode",
|
2020-11-04 23:36:31 +01:00
|
|
|
},
|
|
|
|
|
}
|
2020-10-23 20:37:56 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_modular_type() -> None:
|
2020-11-16 09:44:09 +01:00
|
|
|
unit = parse_buffer(
|
2020-10-23 20:37:56 +02:00
|
|
|
"""
|
|
|
|
|
type Modular_Type is mod 2 ** 9;
|
|
|
|
|
""",
|
2020-12-24 23:14:47 +01:00
|
|
|
rule=librflxlang.GrammarRule.type_declaration_rule,
|
2020-10-23 20:37:56 +02:00
|
|
|
)
|
2020-11-04 23:36:31 +01:00
|
|
|
assert to_dict(unit.root) == {
|
2021-01-09 15:29:14 +01:00
|
|
|
"_kind": "TypeDecl",
|
2020-11-16 09:44:09 +01:00
|
|
|
"definition": {
|
|
|
|
|
"_kind": "ModularTypeDef",
|
|
|
|
|
"mod": {
|
2020-11-20 08:37:00 +01:00
|
|
|
"_kind": "BinOp",
|
|
|
|
|
"left": {"_kind": "NumericLiteral", "_value": "2"},
|
|
|
|
|
"op": {"_kind": "OpPow", "_value": "**"},
|
|
|
|
|
"right": {"_kind": "NumericLiteral", "_value": "9"},
|
2020-11-16 09:44:09 +01:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"identifier": {"_kind": "UnqualifiedID", "_value": "Modular_Type"},
|
2021-08-04 18:55:13 +02:00
|
|
|
"parameters": None,
|
2020-11-04 23:36:31 +01:00
|
|
|
}
|
2020-11-05 18:27:26 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_checksum_attributes() -> None:
|
2020-11-16 09:44:09 +01:00
|
|
|
unit = parse_buffer(
|
2020-11-05 18:27:26 +01:00
|
|
|
"""
|
|
|
|
|
A'Valid_Checksum and B'Valid_Checksum;
|
|
|
|
|
""",
|
2020-12-24 23:14:47 +01:00
|
|
|
rule=librflxlang.GrammarRule.expression_rule,
|
2020-11-05 18:27:26 +01:00
|
|
|
)
|
|
|
|
|
assert to_dict(unit.root) == {
|
2020-11-20 08:37:00 +01:00
|
|
|
"_kind": "BinOp",
|
|
|
|
|
"left": {
|
|
|
|
|
"_kind": "Attribute",
|
|
|
|
|
"expression": {
|
|
|
|
|
"_kind": "Variable",
|
|
|
|
|
"identifier": {
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "A"},
|
|
|
|
|
"package": None,
|
2020-11-20 00:13:52 +01:00
|
|
|
},
|
2020-11-16 09:44:09 +01:00
|
|
|
},
|
2020-11-20 08:37:00 +01:00
|
|
|
"kind": {"_kind": "AttrValidChecksum", "_value": "Valid_Checksum"},
|
|
|
|
|
},
|
|
|
|
|
"op": {"_kind": "OpAnd", "_value": "and"},
|
|
|
|
|
"right": {
|
|
|
|
|
"_kind": "Attribute",
|
|
|
|
|
"expression": {
|
|
|
|
|
"_kind": "Variable",
|
|
|
|
|
"identifier": {
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "B"},
|
|
|
|
|
"package": None,
|
2020-11-20 00:13:52 +01:00
|
|
|
},
|
2020-11-16 09:44:09 +01:00
|
|
|
},
|
2020-11-20 08:37:00 +01:00
|
|
|
"kind": {"_kind": "AttrValidChecksum", "_value": "Valid_Checksum"},
|
2020-11-16 09:44:09 +01:00
|
|
|
},
|
2020-11-05 18:27:26 +01:00
|
|
|
}
|
2020-11-07 23:11:13 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_operator_precedence() -> None:
|
2020-11-16 09:44:09 +01:00
|
|
|
unit = parse_buffer(
|
2020-11-07 23:11:13 +01:00
|
|
|
"""
|
2020-11-10 19:25:00 +01:00
|
|
|
A / 8 >= 46 and A / 8 <= 1500
|
2020-11-07 23:11:13 +01:00
|
|
|
""",
|
2020-12-24 23:14:47 +01:00
|
|
|
rule=librflxlang.GrammarRule.expression_rule,
|
2020-11-07 23:11:13 +01:00
|
|
|
)
|
|
|
|
|
assert to_dict(unit.root) == {
|
2020-11-16 09:44:09 +01:00
|
|
|
"_kind": "BinOp",
|
|
|
|
|
"left": {
|
|
|
|
|
"_kind": "BinOp",
|
2020-11-07 23:11:13 +01:00
|
|
|
"left": {
|
2020-11-16 09:44:09 +01:00
|
|
|
"_kind": "BinOp",
|
2020-11-07 23:11:13 +01:00
|
|
|
"left": {
|
2020-11-16 09:44:09 +01:00
|
|
|
"identifier": {
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "A"},
|
|
|
|
|
"package": None,
|
|
|
|
|
},
|
|
|
|
|
"_kind": "Variable",
|
2020-11-07 23:11:13 +01:00
|
|
|
},
|
2020-11-16 09:44:09 +01:00
|
|
|
"op": {"_kind": "OpDiv", "_value": "/"},
|
|
|
|
|
"right": {"_kind": "NumericLiteral", "_value": "8"},
|
2020-11-07 23:11:13 +01:00
|
|
|
},
|
2020-11-16 09:44:09 +01:00
|
|
|
"op": {"_kind": "OpGe", "_value": ">="},
|
|
|
|
|
"right": {"_kind": "NumericLiteral", "_value": "46"},
|
|
|
|
|
},
|
|
|
|
|
"op": {"_kind": "OpAnd", "_value": "and"},
|
|
|
|
|
"right": {
|
|
|
|
|
"_kind": "BinOp",
|
|
|
|
|
"left": {
|
|
|
|
|
"_kind": "BinOp",
|
2020-11-07 23:11:13 +01:00
|
|
|
"left": {
|
2020-11-16 09:44:09 +01:00
|
|
|
"identifier": {
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "A"},
|
|
|
|
|
"package": None,
|
|
|
|
|
},
|
|
|
|
|
"_kind": "Variable",
|
2020-11-07 23:11:13 +01:00
|
|
|
},
|
2020-11-16 09:44:09 +01:00
|
|
|
"op": {"_kind": "OpDiv", "_value": "/"},
|
|
|
|
|
"right": {"_kind": "NumericLiteral", "_value": "8"},
|
2020-11-07 23:11:13 +01:00
|
|
|
},
|
2020-11-16 09:44:09 +01:00
|
|
|
"op": {"_kind": "OpLe", "_value": "<="},
|
|
|
|
|
"right": {"_kind": "NumericLiteral", "_value": "1500"},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_negative_number() -> None:
|
|
|
|
|
unit = parse_buffer(
|
|
|
|
|
"""
|
|
|
|
|
-16#20_000#
|
|
|
|
|
""",
|
2020-12-24 23:14:47 +01:00
|
|
|
rule=librflxlang.GrammarRule.expression_rule,
|
2020-11-16 09:44:09 +01:00
|
|
|
)
|
|
|
|
|
assert len(unit.diagnostics) == 0, "\n".join(str(d) for d in unit.diagnostics)
|
|
|
|
|
assert to_dict(unit.root) == {
|
|
|
|
|
"_kind": "Negation",
|
|
|
|
|
"data": {"_kind": "NumericLiteral", "_value": "16#20_000#"},
|
2020-11-07 23:11:13 +01:00
|
|
|
}
|
2020-11-20 00:13:52 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_selector_precedence1() -> None:
|
|
|
|
|
unit = parse_buffer(
|
|
|
|
|
"X.B = Z",
|
2020-12-24 23:14:47 +01:00
|
|
|
rule=librflxlang.GrammarRule.extended_expression_rule,
|
2020-11-20 00:13:52 +01:00
|
|
|
)
|
|
|
|
|
assert len(unit.diagnostics) == 0, "\n".join(str(d) for d in unit.diagnostics)
|
|
|
|
|
assert to_dict(unit.root) == {
|
|
|
|
|
"_kind": "BinOp",
|
|
|
|
|
"left": {
|
|
|
|
|
"_kind": "SelectNode",
|
|
|
|
|
"expression": {
|
|
|
|
|
"_kind": "Variable",
|
|
|
|
|
"identifier": {
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "X"},
|
|
|
|
|
"package": None,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"selector": {
|
|
|
|
|
"_kind": "UnqualifiedID",
|
|
|
|
|
"_value": "B",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"op": {"_kind": "OpEq", "_value": "="},
|
|
|
|
|
"right": {
|
|
|
|
|
"_kind": "Variable",
|
|
|
|
|
"identifier": {
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "Z"},
|
|
|
|
|
"package": None,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_selector_precedence2() -> None:
|
|
|
|
|
unit = parse_buffer(
|
|
|
|
|
"X.B'Size",
|
2020-12-24 23:14:47 +01:00
|
|
|
rule=librflxlang.GrammarRule.extended_expression_rule,
|
2020-11-20 00:13:52 +01:00
|
|
|
)
|
|
|
|
|
assert len(unit.diagnostics) == 0, "\n".join(str(d) for d in unit.diagnostics)
|
|
|
|
|
assert to_dict(unit.root) == {
|
|
|
|
|
"_kind": "Attribute",
|
|
|
|
|
"expression": {
|
|
|
|
|
"_kind": "SelectNode",
|
|
|
|
|
"expression": {
|
|
|
|
|
"_kind": "Variable",
|
|
|
|
|
"identifier": {
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "X"},
|
|
|
|
|
"package": None,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"selector": {"_kind": "UnqualifiedID", "_value": "B"},
|
|
|
|
|
},
|
|
|
|
|
"kind": {"_kind": "AttrSize", "_value": "Size"},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_selector_precedence3() -> None:
|
|
|
|
|
unit = parse_buffer(
|
|
|
|
|
"X'Head.B",
|
2020-12-24 23:14:47 +01:00
|
|
|
rule=librflxlang.GrammarRule.extended_expression_rule,
|
2020-11-20 00:13:52 +01:00
|
|
|
)
|
|
|
|
|
assert len(unit.diagnostics) == 0, "\n".join(str(d) for d in unit.diagnostics)
|
|
|
|
|
assert to_dict(unit.root) == {
|
|
|
|
|
"_kind": "SelectNode",
|
|
|
|
|
"expression": {
|
|
|
|
|
"_kind": "Attribute",
|
|
|
|
|
"expression": {
|
|
|
|
|
"_kind": "Variable",
|
|
|
|
|
"identifier": {
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "X"},
|
|
|
|
|
"package": None,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"kind": {"_kind": "AttrHead", "_value": "Head"},
|
|
|
|
|
},
|
|
|
|
|
"selector": {"_kind": "UnqualifiedID", "_value": "B"},
|
|
|
|
|
}
|
2020-11-20 08:18:35 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_suffix_precedence() -> None:
|
|
|
|
|
unit = parse_buffer(
|
|
|
|
|
"2**X'Size",
|
2020-12-24 23:14:47 +01:00
|
|
|
rule=librflxlang.GrammarRule.extended_expression_rule,
|
2020-11-20 08:18:35 +01:00
|
|
|
)
|
|
|
|
|
assert len(unit.diagnostics) == 0, "\n".join(str(d) for d in unit.diagnostics)
|
|
|
|
|
assert to_dict(unit.root) == {
|
|
|
|
|
"_kind": "BinOp",
|
|
|
|
|
"left": {"_kind": "NumericLiteral", "_value": "2"},
|
|
|
|
|
"op": {"_kind": "OpPow", "_value": "**"},
|
|
|
|
|
"right": {
|
|
|
|
|
"_kind": "Attribute",
|
|
|
|
|
"expression": {
|
|
|
|
|
"_kind": "Variable",
|
|
|
|
|
"identifier": {
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "X"},
|
|
|
|
|
"package": None,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"kind": {"_kind": "AttrSize", "_value": "Size"},
|
|
|
|
|
},
|
|
|
|
|
}
|
2021-06-28 15:06:01 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
KEYWORDS = [l for l in rflx_lexer.literals_map if re.match("[A-Za-z_]+", l)]
|
|
|
|
|
|
|
|
|
|
KEYWORD_TESTS = [
|
|
|
|
|
(keyword, t.format(keyword=keyword), r)
|
|
|
|
|
for (t, r) in [
|
|
|
|
|
(
|
2021-06-29 14:45:18 +02:00
|
|
|
"for some {keyword} in {keyword} => {keyword} + 1",
|
2021-06-28 15:06:01 +02:00
|
|
|
librflxlang.GrammarRule.quantified_expression_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
2021-07-23 18:16:07 +02:00
|
|
|
"[for {keyword} in {keyword} if {keyword} > {keyword} => {keyword} - 1]",
|
2021-06-28 15:06:01 +02:00
|
|
|
librflxlang.GrammarRule.comprehension_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
2021-06-29 14:45:18 +02:00
|
|
|
"{keyword} (Variable + {keyword})",
|
2021-06-28 15:06:01 +02:00
|
|
|
librflxlang.GrammarRule.call_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
2021-06-29 14:45:18 +02:00
|
|
|
"{keyword} => {keyword}",
|
2021-06-28 15:06:01 +02:00
|
|
|
librflxlang.GrammarRule.message_aggregate_association_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
"Data.{keyword}",
|
|
|
|
|
librflxlang.GrammarRule.extended_suffix_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
2021-06-29 14:45:18 +02:00
|
|
|
"{keyword} where {keyword} = {keyword}",
|
2021-06-28 15:06:01 +02:00
|
|
|
librflxlang.GrammarRule.extended_suffix_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
"{keyword} => True",
|
|
|
|
|
librflxlang.GrammarRule.aspect_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
2021-06-29 14:45:18 +02:00
|
|
|
"then {keyword} with First => {keyword}'First if {keyword} > {keyword}",
|
2021-06-28 15:06:01 +02:00
|
|
|
librflxlang.GrammarRule.then_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
2021-06-29 14:45:18 +02:00
|
|
|
"{keyword} : {keyword};",
|
2021-10-07 17:11:56 +02:00
|
|
|
librflxlang.GrammarRule.message_field_rule,
|
2021-06-28 15:06:01 +02:00
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
"{keyword} => (1, 30..34)",
|
|
|
|
|
librflxlang.GrammarRule.checksum_association_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
"{keyword}, {keyword}, Elem_1, Elem_2",
|
|
|
|
|
librflxlang.GrammarRule.positional_enumeration_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
"{keyword} => 42",
|
|
|
|
|
librflxlang.GrammarRule.element_value_association_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
2021-06-29 14:45:18 +02:00
|
|
|
"type {keyword} is new {keyword}",
|
2021-06-28 15:06:01 +02:00
|
|
|
librflxlang.GrammarRule.type_declaration_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
2021-06-29 14:45:18 +02:00
|
|
|
"for {keyword} use ({keyword} => {keyword}) if {keyword} > {keyword}",
|
2021-06-28 15:06:01 +02:00
|
|
|
librflxlang.GrammarRule.type_refinement_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
2021-06-29 14:45:18 +02:00
|
|
|
"{keyword} : {keyword}",
|
2021-08-04 18:55:13 +02:00
|
|
|
librflxlang.GrammarRule.parameter_rule,
|
2021-06-28 15:06:01 +02:00
|
|
|
),
|
|
|
|
|
(
|
2021-06-29 14:45:18 +02:00
|
|
|
"with function {keyword} return {keyword}",
|
2021-06-28 15:06:01 +02:00
|
|
|
librflxlang.GrammarRule.formal_function_declaration_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
"{keyword} : Channel with Readable, Writable",
|
|
|
|
|
librflxlang.GrammarRule.channel_declaration_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
2021-06-29 14:45:18 +02:00
|
|
|
"{keyword} : {keyword} renames {keyword}",
|
2021-06-28 15:06:01 +02:00
|
|
|
librflxlang.GrammarRule.renaming_declaration_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
2021-06-29 14:45:18 +02:00
|
|
|
"{keyword} : {keyword} := {keyword}",
|
2021-06-28 15:06:01 +02:00
|
|
|
librflxlang.GrammarRule.variable_declaration_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
2021-06-29 14:45:18 +02:00
|
|
|
"{keyword} := {keyword}",
|
2021-06-28 15:06:01 +02:00
|
|
|
librflxlang.GrammarRule.assignment_statement_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
2021-06-29 14:45:18 +02:00
|
|
|
"{keyword}'Append ({keyword})",
|
2021-06-28 15:06:01 +02:00
|
|
|
librflxlang.GrammarRule.list_attribute_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
"{keyword}'Reset",
|
|
|
|
|
librflxlang.GrammarRule.reset_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
2021-09-22 13:45:34 +02:00
|
|
|
"goto {keyword} if {keyword} = {keyword}",
|
2021-06-28 15:06:01 +02:00
|
|
|
librflxlang.GrammarRule.conditional_transition_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
2021-09-22 13:45:34 +02:00
|
|
|
'goto {keyword} with Desc => "foo"',
|
2021-06-28 15:06:01 +02:00
|
|
|
librflxlang.GrammarRule.transition_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
2021-09-22 13:45:34 +02:00
|
|
|
'goto {keyword} with Desc => "foo"',
|
2021-06-28 15:06:01 +02:00
|
|
|
librflxlang.GrammarRule.transition_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
2021-09-22 13:45:34 +02:00
|
|
|
"begin transition goto {keyword} end {keyword}",
|
2021-06-28 15:06:01 +02:00
|
|
|
librflxlang.GrammarRule.state_body_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
2022-09-19 10:53:25 +02:00
|
|
|
"generic session {keyword} is begin end {keyword}",
|
2021-06-28 15:06:01 +02:00
|
|
|
librflxlang.GrammarRule.session_declaration_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
"""
|
|
|
|
|
package {keyword} is
|
|
|
|
|
end {keyword};
|
|
|
|
|
""",
|
|
|
|
|
librflxlang.GrammarRule.package_declaration_rule,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
"with {keyword};",
|
|
|
|
|
librflxlang.GrammarRule.context_item_rule,
|
|
|
|
|
),
|
|
|
|
|
]
|
|
|
|
|
for keyword in [k.lower() for k in KEYWORDS] + [k.lower().capitalize() for k in KEYWORDS]
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
|
"text,rule",
|
|
|
|
|
[(t, r) for _, t, r in KEYWORD_TESTS],
|
|
|
|
|
ids=[f"{k}->{r[:-5]}" for (k, _, r) in KEYWORD_TESTS],
|
|
|
|
|
)
|
|
|
|
|
def test_keyword_identifiers(text: str, rule: str) -> None:
|
2021-09-22 13:45:34 +02:00
|
|
|
"""
|
|
|
|
|
Test that keywords can be used as identifiers.
|
|
|
|
|
|
|
|
|
|
New keywords must be added to the unqualified_identifier rule in the parser module to allow the
|
|
|
|
|
use as identifiers.
|
|
|
|
|
"""
|
2021-06-28 15:06:01 +02:00
|
|
|
unit = parse_buffer(text, rule=rule)
|
|
|
|
|
assert len(unit.diagnostics) == 0, text + "\n".join(str(d) for d in unit.diagnostics)
|
2022-06-08 11:26:10 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
|
"string,expected",
|
|
|
|
|
[
|
|
|
|
|
(
|
|
|
|
|
"(case A is when V1 => 1, when V2 => 2)",
|
|
|
|
|
{
|
|
|
|
|
"_kind": "CaseExpression",
|
|
|
|
|
"choices": [
|
|
|
|
|
{
|
|
|
|
|
"_kind": "Choice",
|
|
|
|
|
"expression": {"_kind": "NumericLiteral", "_value": "1"},
|
|
|
|
|
"selectors": [
|
|
|
|
|
{
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "V1"},
|
|
|
|
|
"package": None,
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"_kind": "Choice",
|
|
|
|
|
"expression": {"_kind": "NumericLiteral", "_value": "2"},
|
|
|
|
|
"selectors": [
|
|
|
|
|
{
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "V2"},
|
|
|
|
|
"package": None,
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
"expression": {
|
|
|
|
|
"_kind": "Variable",
|
|
|
|
|
"identifier": {
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "A"},
|
|
|
|
|
"package": None,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
"(case A is when T::V1 => 1, when T::V2 => 2)",
|
|
|
|
|
{
|
|
|
|
|
"_kind": "CaseExpression",
|
|
|
|
|
"choices": [
|
|
|
|
|
{
|
|
|
|
|
"_kind": "Choice",
|
|
|
|
|
"expression": {"_kind": "NumericLiteral", "_value": "1"},
|
|
|
|
|
"selectors": [
|
|
|
|
|
{
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "V1"},
|
|
|
|
|
"package": {"_kind": "UnqualifiedID", "_value": "T"},
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"_kind": "Choice",
|
|
|
|
|
"expression": {"_kind": "NumericLiteral", "_value": "2"},
|
|
|
|
|
"selectors": [
|
|
|
|
|
{
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "V2"},
|
|
|
|
|
"package": {"_kind": "UnqualifiedID", "_value": "T"},
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
"expression": {
|
|
|
|
|
"_kind": "Variable",
|
|
|
|
|
"identifier": {
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "A"},
|
|
|
|
|
"package": None,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
"(case A is when V1 | T::V2 => 1, when V3 | T::V4 => 2)",
|
|
|
|
|
{
|
|
|
|
|
"_kind": "CaseExpression",
|
|
|
|
|
"choices": [
|
|
|
|
|
{
|
|
|
|
|
"_kind": "Choice",
|
|
|
|
|
"expression": {"_kind": "NumericLiteral", "_value": "1"},
|
|
|
|
|
"selectors": [
|
|
|
|
|
{
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "V1"},
|
|
|
|
|
"package": None,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "V2"},
|
|
|
|
|
"package": {"_kind": "UnqualifiedID", "_value": "T"},
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"_kind": "Choice",
|
|
|
|
|
"expression": {"_kind": "NumericLiteral", "_value": "2"},
|
|
|
|
|
"selectors": [
|
|
|
|
|
{
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "V3"},
|
|
|
|
|
"package": None,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "V4"},
|
|
|
|
|
"package": {"_kind": "UnqualifiedID", "_value": "T"},
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
"expression": {
|
|
|
|
|
"_kind": "Variable",
|
|
|
|
|
"identifier": {
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "A"},
|
|
|
|
|
"package": None,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
"(case A is when 1 => 8, when 2 => 16)",
|
|
|
|
|
{
|
|
|
|
|
"_kind": "CaseExpression",
|
|
|
|
|
"choices": [
|
|
|
|
|
{
|
|
|
|
|
"_kind": "Choice",
|
|
|
|
|
"expression": {"_kind": "NumericLiteral", "_value": "8"},
|
|
|
|
|
"selectors": [{"_kind": "NumericLiteral", "_value": "1"}],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"_kind": "Choice",
|
|
|
|
|
"expression": {"_kind": "NumericLiteral", "_value": "16"},
|
|
|
|
|
"selectors": [{"_kind": "NumericLiteral", "_value": "2"}],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
"expression": {
|
|
|
|
|
"_kind": "Variable",
|
|
|
|
|
"identifier": {
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "A"},
|
|
|
|
|
"package": None,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
"(case A is when 1 | 2 => 8, when 3 | 4 => 16)",
|
|
|
|
|
{
|
|
|
|
|
"_kind": "CaseExpression",
|
|
|
|
|
"choices": [
|
|
|
|
|
{
|
|
|
|
|
"_kind": "Choice",
|
|
|
|
|
"expression": {"_kind": "NumericLiteral", "_value": "8"},
|
|
|
|
|
"selectors": [
|
|
|
|
|
{"_kind": "NumericLiteral", "_value": "1"},
|
|
|
|
|
{"_kind": "NumericLiteral", "_value": "2"},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"_kind": "Choice",
|
|
|
|
|
"expression": {"_kind": "NumericLiteral", "_value": "16"},
|
|
|
|
|
"selectors": [
|
|
|
|
|
{"_kind": "NumericLiteral", "_value": "3"},
|
|
|
|
|
{"_kind": "NumericLiteral", "_value": "4"},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
"expression": {
|
|
|
|
|
"_kind": "Variable",
|
|
|
|
|
"identifier": {
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "A"},
|
|
|
|
|
"package": None,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
"(case A is when V1 => Length + 2, when V2 => 2 * Length)",
|
|
|
|
|
{
|
|
|
|
|
"_kind": "CaseExpression",
|
|
|
|
|
"choices": [
|
|
|
|
|
{
|
|
|
|
|
"_kind": "Choice",
|
|
|
|
|
"expression": {
|
|
|
|
|
"_kind": "BinOp",
|
|
|
|
|
"left": {
|
|
|
|
|
"_kind": "Variable",
|
|
|
|
|
"identifier": {
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "Length"},
|
|
|
|
|
"package": None,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"op": {"_kind": "OpAdd", "_value": "+"},
|
|
|
|
|
"right": {"_kind": "NumericLiteral", "_value": "2"},
|
|
|
|
|
},
|
|
|
|
|
"selectors": [
|
|
|
|
|
{
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "V1"},
|
|
|
|
|
"package": None,
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"_kind": "Choice",
|
|
|
|
|
"expression": {
|
|
|
|
|
"_kind": "BinOp",
|
|
|
|
|
"left": {"_kind": "NumericLiteral", "_value": "2"},
|
|
|
|
|
"op": {"_kind": "OpMul", "_value": "*"},
|
|
|
|
|
"right": {
|
|
|
|
|
"_kind": "Variable",
|
|
|
|
|
"identifier": {
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "Length"},
|
|
|
|
|
"package": None,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"selectors": [
|
|
|
|
|
{
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "V2"},
|
|
|
|
|
"package": None,
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
"expression": {
|
|
|
|
|
"_kind": "Variable",
|
|
|
|
|
"identifier": {
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "A"},
|
|
|
|
|
"package": None,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
"(case A is when True => F1, when False => F2 or F3)",
|
|
|
|
|
{
|
|
|
|
|
"_kind": "CaseExpression",
|
|
|
|
|
"choices": [
|
|
|
|
|
{
|
|
|
|
|
"_kind": "Choice",
|
|
|
|
|
"expression": {
|
|
|
|
|
"_kind": "Variable",
|
|
|
|
|
"identifier": {
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "F1"},
|
|
|
|
|
"package": None,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"selectors": [
|
|
|
|
|
{
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "True"},
|
|
|
|
|
"package": None,
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"_kind": "Choice",
|
|
|
|
|
"expression": {
|
|
|
|
|
"_kind": "BinOp",
|
|
|
|
|
"left": {
|
|
|
|
|
"_kind": "Variable",
|
|
|
|
|
"identifier": {
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "F2"},
|
|
|
|
|
"package": None,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"op": {"_kind": "OpOr", "_value": "or"},
|
|
|
|
|
"right": {
|
|
|
|
|
"_kind": "Variable",
|
|
|
|
|
"identifier": {
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "F3"},
|
|
|
|
|
"package": None,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"selectors": [
|
|
|
|
|
{
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "False"},
|
|
|
|
|
"package": None,
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
"expression": {
|
|
|
|
|
"_kind": "Variable",
|
|
|
|
|
"identifier": {
|
|
|
|
|
"_kind": "ID",
|
|
|
|
|
"name": {"_kind": "UnqualifiedID", "_value": "A"},
|
|
|
|
|
"package": None,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
)
|
|
|
|
|
def test_extended_case_expression(string: str, expected: Dict[str, str]) -> None:
|
|
|
|
|
actual = parse(string, rule=librflxlang.GrammarRule.extended_expression_rule)
|
|
|
|
|
assert actual == expected
|