Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Dereferenced Function/Method Returns in Grammar #59

Merged
Merged
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
4 changes: 2 additions & 2 deletions blark/iec.lark
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,7 @@ UNARY_OPERATOR: LOGICAL_NOT
| MINUS
| PLUS

function_call: symbolic_variable "(" [ param_assignment ( "," param_assignment )* ","? ] ")"
function_call: symbolic_variable "(" [ param_assignment ( "," param_assignment )* ","? ] ")" DEREFERENCED?

?primary_expression: "(" expression ")" -> parenthesized_expression
| function_call
Expand Down Expand Up @@ -749,7 +749,7 @@ reset_statement: _variable "R="i expression ";"+
reference_assignment_statement: _variable "REF="i expression ";"+

// method ::= expression [DEREFERENCED] '.' _identifier '(' ')';
method_statement: symbolic_variable "(" ")" ";"+
method_statement: symbolic_variable "(" ")" DEREFERENCED? ";"+
Copy link
Owner

Choose a reason for hiding this comment

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

Looks like it's time to get rid of method_statement entirely.

function_call_statement (using function_call) handles everything it does and more, so having both just makes for ambiguity in the grammar.

I'll make an issue to remove it along with its related MethodStatement class.


// B.3.2.2
return_statement.1: "RETURN"i ";"*
Expand Down
8 changes: 8 additions & 0 deletions blark/tests/source/dereference_method.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
METHOD DoSomething
VAR
Something : BOOL;
END_VAR

Something := anObject.WriteLine(THIS^.something.t, THIS^.GetTagName()^, INT_TO_STRING(BOOL_TO_INT(THIS^.someAttribute)));

END_METHOD
12 changes: 11 additions & 1 deletion blark/tests/test_transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1072,7 +1072,17 @@ def test_action_roundtrip(rule_name, value):
)),
param("chained_function_call_statement", tf.multiline_code_block(
"""
uut.call1().call2().call3.call4().done();
uut.call1().call2().call3().call4().done();
"""
)),
param("chained_function_call_statement", tf.multiline_code_block(
"""
uut.call1()^.call2().call3()^.call4().done();
"""
)),
param("chained_function_call_statement", tf.multiline_code_block(
"""
uut.call1()^.call2(A := 1).call3(B := 2)^.call4().done();
"""
)),
],
Expand Down
14 changes: 13 additions & 1 deletion blark/transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -1587,6 +1587,7 @@ def __str__(self) -> str:
class FunctionCall(Expression):
name: SymbolicVariable
parameters: List[ParameterAssignment]
dereferenced: bool
meta: Optional[Meta] = meta_field()

@property
Expand Down Expand Up @@ -1621,6 +1622,12 @@ def from_lark(
first_parameter: Optional[ParameterAssignment] = None,
*remaining_parameters: ParameterAssignment,
Copy link
Owner

Choose a reason for hiding this comment

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

Technically the remaining_parameters annotation needs updating here because it can now contain a lark.Token as well (holding that semi-colon ";"). Then static analyzers will complain that parameters is no longer compatible with List[ParameterAssignment], ...

Let's just roll with this and maybe clean it up later - there are much bigger fish to fry!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think that's a fair point, though, @klauer... I had toyed with it, but decided the same about "bigger fish" (at least for this moment in time). Do you have thoughts on a better name? I'd be happy to lob something in there in upcoming changes.

Copy link
Owner

Choose a reason for hiding this comment

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

I couldn't think of a way to express it in words - sometimes code is more succinct.
I think this might be preferable:

    @staticmethod
    def from_lark(
        name: SymbolicVariable,
        *params: Union[ParameterAssignment, lark.Token, None],
    ) -> FunctionCall:
        # Condition parameters (which may be `None`) to represent empty tuple
        if params and params[0] is None:
            params = params[1:]
        dereferenced = bool(params and params[-1] == "^")
        if dereferenced:
            params = params[:-1]

        return FunctionCall(
            name=name,
            parameters=typing.cast(List[ParameterAssignment], list(params)),
            dereferenced=dereferenced,
        )

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

OK! I'm gonna roll this in to the next bit of work I do. 👍

) -> FunctionCall:
# Remove the Dereference Token if Present in the Remaining Parameters
dereferenced = False
if remaining_parameters:
if str(remaining_parameters[-1]) == "^":
dereferenced = True
remaining_parameters = remaining_parameters[:-1]
# Condition parameters (which may be `None`) to represent empty tuple
if first_parameter is None:
parameters = []
Expand All @@ -1630,11 +1637,15 @@ def from_lark(
return FunctionCall(
name=name,
parameters=parameters,
dereferenced=dereferenced
)

def __str__(self) -> str:
dereference = ""
parameters = ", ".join(str(param) for param in self.parameters)
return f"{self.name}({parameters})"
if self.dereferenced:
dereference = "^"
return f"{self.name}({parameters}){dereference}"


@dataclass
Expand Down Expand Up @@ -2620,6 +2631,7 @@ def from_lark(
return FunctionCallStatement(
name=invocation.name,
parameters=invocation.parameters,
dereferenced=invocation.dereferenced,
meta=invocation.meta,
)

Expand Down