diff --git a/blark/iec.lark b/blark/iec.lark index 145589a..567883d 100644 --- a/blark/iec.lark +++ b/blark/iec.lark @@ -287,7 +287,7 @@ indirection_type: REFERENCE_TO | REFERENCE_TO POINTER_TO+ pointer_type: POINTER_TO+ -simple_spec_init: [ indirection_type ] simple_specification [ ":=" expression ] +simple_spec_init: ( simple_specification | indirect_simple_specification ) [ ":=" expression ] simple_specification: elementary_type_name | simple_type_name @@ -532,7 +532,12 @@ string_type_specification: (STRING | WSTRING) [ string_spec_length ] // B.1.5.1 ?derived_function_name: IDENTIFIER -indirect_simple_specification: [ indirection_type ] simple_specification +indirect_simple_specification: [ indirection_type ] simple_specification [ input_param_args ] + +input_param_args: "(" [ input_param_assignment ( "," input_param_assignment )* ","? ] ")" + +input_param_assignment: variable_name ":=" [ expression ] + | expression function_declaration: "FUNCTION"i [ access_specifier ] derived_function_name [ ":" indirect_simple_specification ] ";"* [ function_var_block+ ] [ function_body ] "END_FUNCTION"i ";"* diff --git a/blark/tests/test_transformer.py b/blark/tests/test_transformer.py index 004b18c..26fe0df 100644 --- a/blark/tests/test_transformer.py +++ b/blark/tests/test_transformer.py @@ -115,6 +115,7 @@ def test_check_unhandled_rules(grammar: lark.Lark): # handled as tree "global_var_list", "var_body", + "input_param_args", } todo_rules = set() @@ -367,6 +368,8 @@ def test_bool_literal_roundtrip(name, value, expected): param("simple_type_declaration", "TypeName : POINTER TO INT"), param("simple_type_declaration", "TypeName : POINTER TO POINTER TO INT"), param("simple_type_declaration", "TypeName : REFERENCE TO POINTER TO INT"), + param("simple_type_declaration", "TypeName : POINTER TO fbSomething(1, 2, 3)"), + param("simple_type_declaration", "TypeName : POINTER TO fbSomething(1, 2, C := 4)"), # noqa: E501 param("simple_type_declaration", "TypeName EXTENDS a.b : POINTER TO INT"), param("subrange_specification", "TypeName"), # aliased and not usually hit param("subrange_type_declaration", "TypeName : INT (1..2)"), diff --git a/blark/transform.py b/blark/transform.py index d82375d..c0a747f 100644 --- a/blark/transform.py +++ b/blark/transform.py @@ -312,10 +312,9 @@ def from_init( ) spec_type = cls.from_spec(init.spec) if isinstance(init, TypeInitialization): - full_type_name = join_if(init.indirection, " ", spec_type.full_type_name) return cls( base_type_name=spec_type.base_type_name, - full_type_name=full_type_name, + full_type_name=spec_type.full_type_name, context=init, ) return spec_type @@ -1174,8 +1173,7 @@ class TypeInitialization(TypeInitializationBase): TypeName := Value1 STRING[100] := "value" """ - indirection: Optional[IndirectionType] - spec: SimpleSpecification + spec: Union[SimpleSpecification, IndirectSimpleSpecification] value: Optional[Expression] meta: Optional[Meta] = meta_field() @@ -1581,13 +1579,47 @@ class IndirectSimpleSpecification(TypeSpecificationBase): POINTER TO TypeName REFERENCE TO TypeName REFERENCE TO POINTER TO TypeName + + Initialization parameters such as these are parsed but otherwise ignored + by TwinCAT:: + + POINTER TO TypeName(1, 2) + POINTER TO TypeName(1, 2, C := 4) """ indirection: Optional[IndirectionType] type: SimpleSpecification + init_parameters: Optional[List[InputParameterAssignment]] meta: Optional[Meta] = meta_field() + @staticmethod + def from_lark( + indirection: Optional[IndirectionType], + type_: SimpleSpecification, + init_parameters_tree: Optional[lark.Tree], + ) -> IndirectSimpleSpecification: + if init_parameters_tree is None: + init_parameters = None + else: + init_parameters = typing.cast( + List[InputParameterAssignment], + list(init_parameters_tree.children) + ) + return IndirectSimpleSpecification( + indirection, + type_, + init_parameters, + ) + def __str__(self) -> str: - return join_if(self.indirection, " ", self.type) + full_type = join_if(self.indirection, " ", self.type) + if not self.init_parameters: + return full_type + + initializers = ", ".join( + str(init) + for init in self.init_parameters + ) + return f"{full_type}({initializers})" # _array_spec_type @@ -2673,7 +2705,7 @@ class ParameterAssignment: @dataclass -@_rule_handler("param_assignment") +@_rule_handler("param_assignment", "input_param_assignment") class InputParameterAssignment(ParameterAssignment): """ An input parameter in a function call.