%start      stmt_list
%token      NAME QUOTE_ SQUOTE_ STRING _QUOTE _SQUOTE NUMBER TRUE  FALSE  BRACKET_ _BRACKET COMMA BRACE_ _BRACE SEPARATOR BEGIN END
%left       PLUS  MINUS
%left       TIMES  DIVIDE
%nonassoc   VALUEOF LABELOF

%%

stmt_list       : stmt
                    { $$ = [$1]; }
                | stmt_list stmt
                    { $$ = $1; $$[] = $2; }
                ;

ex_stmt         : BEGIN expr END
                    { $$ = new Nodes\ExpressionStatementNode($2); }
                ;

stmt            : ex_stmt
                | STRING
                    { $$ = new Nodes\EncapsulatedStringNode($1); }
                | identifier
                ;

expr            : bracket_expr
                | func_call
                | identifier
                | value
                | op_expr
                | value_expr
                | label_expr
                ;

variable        : NAME
                    { $$ = new Nodes\NameNode($1); }
                ;

identifier      : BRACE_ NAME _BRACE
                    { $$ = new Nodes\IdentifierNode("", $2); }
                | BRACE_ NAME SEPARATOR NAME _BRACE
                    { $$ = new Nodes\IdentifierNode($2, $4); }
                ;

value           : strval
                    { $$ = new Nodes\StringNode($1); }
                | NUMBER
                    { $$ = new Nodes\NumberNode($1); }
                | TRUE
                    { $$ = new Nodes\BooleanNode(true); }
                | FALSE
                    { $$ = new Nodes\BooleanNode(false); }
                ;

strval          : QUOTE_ STRING _QUOTE
                    {$$ = stripslashes($2);}
                | SQUOTE_ STRING _SQUOTE
                    {$$ = stripslashes($2);}
                ;

op_expr         : expr  PLUS  expr
                    { $$ = new Nodes\ArithmeticNode(Nodes\OperatorNode::OP_PLUS, $1, $3); }
                | expr  MINUS expr
                    { $$ = new Nodes\ArithmeticNode(Nodes\OperatorNode::OP_MINUS, $1, $3); }
                | expr  TIMES expr
                    { $$ = new Nodes\ArithmeticNode(Nodes\OperatorNode::OP_TIMES, $1, $3); }
                | expr  DIVIDE expr
                    { $$ = new Nodes\ArithmeticNode(Nodes\OperatorNode::OP_DIVIDE, $1, $3); }
                | PLUS  expr            %prec  '*'
                    { $$ = new Nodes\UnaryNode(Nodes\OperatorNode::OP_PLUS, $2); }
                | MINUS expr            %prec  '*'
                    { $$ = new Nodes\UnaryNode(Nodes\OperatorNode::OP_MINUS, $2); }
                ;

value_expr      : VALUEOF variable
                    { $$ = new Nodes\FieldNode(Nodes\FieldNode::TYPE_VALUE, $2); }
                ;
label_expr      : LABELOF variable
                    { $$ = new Nodes\FieldNode(Nodes\FieldNode::TYPE_LABEL, $2); }
                ;

bracket_expr    : BRACKET_ expr _BRACKET
                    { $$ = $2; }
                ;

func_call       : NAME BRACKET_ arg_list _BRACKET
                    { $$ = new Nodes\FunctionCallNode($1, $3); }
                ;

arg_list        : /* empty list */
                    { $$ = []; }
                | expr
                    { $$ = [$1]; }
                | arg_list COMMA expr
                    { $$ = $1; $$[] = $3; }
%%
