PLC-lang / rusty

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

"Cannot generate literal initializer for 'mainProg.config': Value cannot be derived" #707

Closed rarris closed 9 months ago

rarris commented 1 year ago
PROGRAM mainProg
VAR
END_VAR
VAR CONSTANT
config : ARRAY[1..2] OF struct1 :=
(var1:=1),
(var1:=1, channel:=10(global_const), 8(global_const));
END_VAR
END_PROGRAM
TYPE struct1 :
STRUCT
   var1 : DINT;
   channel : ARRAY[1..16] OF DINT; 
END_STRUCT
END_TYPE
VAR_GLOBAL CONSTANT
global_const : DWORD  := 16#0001;
END_VAR

error: Cannot generate literal initializer for 'mainProg.config': Value cannot be derived Error: SyntaxError { message: "Some initial values were not generated", range: [SourceRange { range: 0..0 }], err_no: codegen__general }

struct array initialization is the problem - channel:=10(global_const), 8(global_const)

99NIMI commented 1 year ago

@ghaith @riederm as rares described the array initialization is the problem 1: channel:=10(global_const), 8(global_const) -> doesn't work 2: channel:=(10(global_const), 8(global_const))-> works after we added the () 3: arr : ARRAY [1..2] OF DINT := 1, 2, 3;-> works without the () the problem is how our parser works

why option 3 works, if our parser matches the ARRAY keyword, no matter what comes after := we will generate an ExpressionList for it, until we match for semicolon -> this is the reason we don't need to use () for the initializer

why option 1 does't work!, there is no ARRAY keyword in this context, we would only parse for an ExpressionList if we match (

the question is how should we handle this ? should we modify the parser and also generate an ExpressionList for something like this -> 1,2,3; until we match semicolon, this would fix the error or is this an valid error and () is needed in this case

riederm commented 1 year ago

yes thats the parsers fault ...

The corect AST would be:

Assignment(
   Reference, 
   ExpressionList [
      MultipliedStatement, 
      MultipliedStatement]
)

On the other hand, this only makes sense, if this is the last assignment in the struct initialization ...

config : ARRAY[1..2] OF struct1 :=
    (var1:=1),
    (var1:=1, channel:=10(global_const), 8(global_const));
            ^                          ^   
            these two comas are in the same scope?!

I think this would not work:

config : ARRAY[1..2] OF struct1 :=
    (var1:=1),
    (var1:=1, channel:=10(global_const), 8(global_const), last_field := 3);
            ^                          ^                ^
     how can we know that the channel-assignment started an expression list that only lasts for 2 segments?

:question: is this worth the parser effort, when some simple brackets creates an unambiguous situation? :question:

riederm commented 1 year ago

so in short, my vote is: this is a valid error and () is needed in this case. Without brackets, the coma starts the assignment to the next struct field.

what do you guys think?

99NIMI commented 1 year ago

my first thought was also that this is an error array initialization without () feels a little bit unnatural to me, normally you would see something like {1,2,3,...}in other languages and i don't think the effort would be worth it

99NIMI commented 1 year ago
error: Array initializer must be an initializer list!
   ┌─ main.st:29:2
   │
29 │   arr := 1, 2;
   │   ^^^ Array initializer must be an initializer list!

error: Expected identifier or '('
   ┌─ main.st:29:12
   │
29 │   arr := 1, 2;
   │             ^ Expected identifier or '('

current implementation of the validation will report the error like C

rarris commented 1 year ago

apparently we have another type of struct initialization ...

PROGRAM mainProg
VAR
var_init : ARRAY[0..15] OF STRUCT1 := (name:='text'),(node:=1),(myArr:=(x1:=FALSE,x2:=TRUE));
END_VAR
END_PROGRAM
TYPE STRUCT1 :
     STRUCT
        var10 : BOOL;
        name : STRING[31];
        node : DINT;
        number : DINT;
        myArr : ARRAY[0..10] OF STRUCT2;
    END_STRUCT
END_TYPE
TYPE STRUCT2 :
     STRUCT
        x1 : BOOL;
        x2 : BOOL;
        x3 : DINT;
        x4 : DINT;
    END_STRUCT
END_TYPE

error: Cannot generate literal initializer for 'mainProg.var_init': Value cannot be derived Error: SyntaxError { message: "Some initial values were not generated", range: [SourceRange { range: 0..0 }], err_no: codegen__general }