PLC-lang / rusty

Structured Text Parser and LLVM Frontend
GNU Lesser General Public License v3.0
181 stars 47 forks source link

Chained assignment `a := b := c` #1173

Open mhasel opened 1 month ago

mhasel commented 1 month ago

Is your feature request related to a problem? Please describe. While - as far as I can tell from the grammar in the standard - this functionality is not required, it is supported by CodeSys and used in some of our internal test projects.

Section 6.6.1.2.2 says the following about the assignment operator's behaviour:

a) In textual form (also partially applicable to graphical languages) the assignment operator may be “:= ” which means the value of the expression on the right side of the operator is written to the variable on the left side of the operator or “ => “ which means the value on the left side of the operator is written to the variable on the right side of the operator. ... This also sounds more like a statement rather than an expression.

If we decide to support this for CodeSys compatibility, we could take the C approach here, where assignments are expressions and return the RValue of the left-hand-side's value:

6.5.16 Assignment operators Semantics 3 An assignment operator stores a value in the object designated by the left operand. An assignment expression has the value of the left operand after the assignment,111) but is not an lvalue. The type of an assignment expression is the type the left operand would have after lvalue conversion. The side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands. The evaluations of the operands are unsequenced.

That would mean a := b := c is valid code, but (a := b) := c is not.

Another option would be C++ behaviour, where assignment expressions return LValues referencing the left-hand-side, which means the second example would also compile:

5.17: ...All require a modifiable lvalue as their left operand and return an lvalue referring to the left operand...

Chaining VAR_OUTPUT assignments doesn't seem to be supported in CodeSys either, e.g. myFB( x => y => z) won't compile. If we were to define the result of an assignment-expression as RValues of the value stored/LValue of the left (right for =>) operand, then myFB( x => y => z) could theoretically also work.

Should we support this and if so, which behaviour do we want here?

Current behaviour

If we try to compile the following example

FUNCTION main: DINT
VAR
    u, v: USINT;
END_VAR
    u := v := 16#FFFF;
END_FUNCTION

we end up with the following error during the codegen phase:

error[E071]: Expected Struct-literal, got Assignment {
    left: ReferenceExpr {
        kind: Member(
            Identifier {
                name: "v",
            },
        ),
        base: None,
    },
    right: LiteralInteger {
        value: 65535,
    },
}