diff --git a/blark/iec.lark b/blark/iec.lark index 02e6696..45d1e02 100644 --- a/blark/iec.lark +++ b/blark/iec.lark @@ -722,6 +722,7 @@ _statement: ";" | reset_statement | reference_assignment_statement | return_statement + | chained_function_call_statement | function_call_statement | if_statement | case_statement @@ -752,6 +753,8 @@ return_statement.1: "RETURN"i ";"* function_call_statement: function_call ";"+ +chained_function_call_statement: function_call ("." function_call)+ ";"+ + param_assignment: [ LOGICAL_NOT ] variable_name "=>" [ expression ] -> output_parameter_assignment | variable_name ":=" [ expression ] | expression diff --git a/blark/tests/source/object_oriented_dotaccess.st b/blark/tests/source/object_oriented_dotaccess.st new file mode 100644 index 0000000..9520b6c --- /dev/null +++ b/blark/tests/source/object_oriented_dotaccess.st @@ -0,0 +1,19 @@ +(* This program uses some object-oriented function-block with multiline access. *) +PROGRAM oop_test +VAR + uut : SomeFunctionBlock; +END_VAR + +// Use an object that has a different method called on each line +uut.DoSomething(input_1:='foo', input_2:='bar') + .DoSomethingElse(input_1:=5) + .Finish(); + +// Or perhaps something that's a little more tame +uut.DoSomething(input_1:='foo', input_2:='bar') + .DoSomethingElse(input_1:=5).Finish(); + +// Or something tamer, still +uut.DoSomething(input_1:='foo', input_2:='bar').DoSomethingElse(input_1:=5).Finish(); + +END_PROGRAM diff --git a/blark/tests/test_transformer.py b/blark/tests/test_transformer.py index 794cfcc..9bc1afe 100644 --- a/blark/tests/test_transformer.py +++ b/blark/tests/test_transformer.py @@ -1073,6 +1073,11 @@ def test_action_roundtrip(rule_name, value): END_FOR """ )), + param("chained_function_call_statement", tf.multiline_code_block( + """ + uut.call1().call2().call3.call4().done(); + """ + )), ], ) def test_statement_roundtrip(rule_name, value): diff --git a/blark/transform.py b/blark/transform.py index 721b101..e37d9a7 100644 --- a/blark/transform.py +++ b/blark/transform.py @@ -2604,6 +2604,23 @@ def __str__(self): return f"{invoc};" +@dataclass +@_rule_handler("chained_function_call_statement", comments=True) +class ChainedFunctionCallStatement(Statement): + invocations: List[FunctionCall] + meta: Optional[Meta] = meta_field() + + @staticmethod + def from_lark(*invocations: FunctionCall) -> ChainedFunctionCallStatement: + return ChainedFunctionCallStatement( + invocations=list(invocations) + ) + + def __str__(self) -> str: + invoc = ".".join(str(invocation) for invocation in self.invocations) + return f"{invoc};" + + @dataclass @_rule_handler("else_if_clause", comments=True) class ElseIfClause: