grammar{
    start: (include | vardecl | definition | funcdecl | newline)+;

    definition : type_specifier ID ASSIGN atomvalue;

    include: INCLUDE STRVALUE newline+;

    statement: ((vardecl | assignment | return | func_call) newline) | (ifelse | while) | (newline) @Rm;

    vardecl: type_specifier ID;

    assignment
        :   lvalue ASSIGN expression;

    expression
        :   binary_operation;

	binary_operation
	    :   disjunction;

    //lvalue
    //    :   IDENTIFIER
    //    |   IDENTIFIER LSQUARE expression RSQUARE;

    disjunction
        :   (disjunction OR conjunction)
        |   conjunction;

    conjunction
        :   (conjunction AND comparison)
        |   comparison;

    comparison
        :   (comparison EQ relation)
        |   (comparison NEQ relation)
        |   relation;

    relation
        :   (relation LT sum)
        |   (relation GT sum)
        |   (relation LE sum)
        |   (relation GE sum)
        |   sum;

    sum
        :   (sum PLUS term)
        |   (sum MINUS term)
        |   term;

    term
        :   (term STAR factor)
        |   (term SLASH factor)
        |   factor;

    factor
        :   logical_not
        |   invert_sign
        |   keep_sign
        |   primary;
	logical_not
	    :   NOT primary;
	invert_sign
	    :   MINUS primary;
	keep_sign
	    :   PLUS primary;

    primary
        :   parenthesized
        |   rvalue
        |   func_call
        |   atomvalue;

    parenthesized
        :   LPAREN expression RPAREN;

    atomvalue: string | integer | float | bool | type_specifier | actionname | deref;

    deref: QUESTIONMARK ANYTHING?;

    type_specifier: INT | FLOAT | BOOL | STRING | TYPE | ACTION | ELEMENT;
    actionname: EXCLAMATION (IF_NODE | WHILE_NODE | ASSIGN_NODE | CALL_NODE | BREAK_NODE | CONTINUE_NODE | RETURN_NODE | RESOLVE_NODE | ACCESS_NODE | CONSTANT_NODE | GLOBAL_NODE | DECLARE_NODE | INPUT_NODE | OUTPUT_NODE);

    string: (STRVALUE|LONG_STRVALUE);

    integer: DEC_NUMBER;
    float: FLOAT_NUMBER;

    rvalue
        : (rvalue LSQUARE expression RSQUARE)
        | ID;

    lvalue: ID;

    func_call: rvalue LPAREN (expression (COMMA expression)*)? RPAREN;

    ifelse: IF expression COLON newline block
        (indent ELIF expression COLON newline block)#[0]*
        (indent ELSE COLON newline block)#[0]?;

    while: WHILE expression COLON newline block;

    block: (indent statement)#+;

    func_body: block;

    funcdecl: func_type FUNCTION func_name LPAREN (parameter (COMMA parameter)*)? RPAREN ((COLON newline func_body) | (ASSIGN QUESTIONMARK ANYTHING newline))?;

    func_type: type_specifier | void;

    func_name: ID;

    void: VOID;

    parameter: ID COLON type_specifier;

    return: RETURN expression?;

    indent: TAB;

    bool: TRUE | FALSE;

    newline: COMM* NEWLINE;

    tokens{
        // TOKENS (written in CAPS)
        ID: '[a-zA-Z_][a-zA-Z_0-9.]*';
        ANYTHING: '[a-zA-Z_0-9/.]+';
        VOID: 'Void';
        INCLUDE: 'include';

        ELEMENT: 'Element';

        IF_NODE: 'if';
        WHILE_NODE: 'while';
        ASSIGN_NODE: 'assign';
        CALL_NODE: 'call';
        BREAK_NODE: 'break';
        CONTINUE_NODE: 'continue';
        RETURN_NODE: 'return';
        RESOLVE_NODE: 'resolve';
        ACCESS_NODE: 'access';
        CONSTANT_NODE: 'constant';
        INPUT_NODE: 'input';
        OUTPUT_NODE: 'output';
        GLOBAL_NODE: 'global';
        DECLARE_NODE: 'declare';

        FUNCTION: 'function';
        RETURN: 'return';

        WHILE: 'while';
        IF: 'if';
        ELSE: 'else';
        ELIF: 'elif';

        INT: 'Integer';
        FLOAT: 'Float';
        BOOL: 'Boolean';
        STRING: 'String';
        TYPE: 'Type';
        ACTION: 'Action';

        PLUS: '\+';
        MINUS: '-';
        STAR: '\*';
        SLASH: '/';
        EXCLAMATION: '!';
        QUESTIONMARK: '\?';
        COLON: ':';
        SEMICOLON: ';';
        ASSIGN: '=';
        COMMA: ',';
        LE: '<=';
        GE: '>=';
        LT: '<';
        GT: '>';
        LPAREN: '\(';
        RPAREN: '\)';
        LCURLY: '{';
        RCURLY: '}';
        LSQUARE: '\[';
        RSQUARE: ']';
        OR: 'or';
        AND: 'and';
        NOT: 'not';
        EQ: '==';
        NEQ: '!=';

        DEC_NUMBER: '[+-]?(0|[1-9]\d*[lL]?)';
        POS_DEC_NUMBER: '(0|[1-9]\d*)';

        FLOAT_NUMBER: '[+-]?((\d+\.\d*|\.\d+)([eE][-+]?\d+)?|\d+[eE][-+]?\d+)';

        STRVALUE : 'u?r?("(?!"").*?(?<!\\)(\\\\)*?"|\'(?!\'\').*?(?<!\\)(\\\\)*?\')';
        LONG_STRVALUE : '(?s)u?r?(""".*?(?<!\\)(\\\\)*?"""|\'\'\'.*?(?<!\\)(\\\\)*?\'\'\')';

        NEWLINE: '(\r?\n)+';
        WS: '[ ]+' @Impl;

        TAB: '\t';

        TRUE: 'True';
        FALSE: 'False';

        COMM: '[\t]*//[^\n]*';
    }
}
