/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

grammar IvannosysGrammar;

@header {
    import java.util.HashMap;
    import java.util.Stack;
}
@members {
     HashMap<String, String> decfunc = new HashMap<>();    
     HashMap<String, String> decmet = new HashMap<>();    
     HashMap<String, String> decvars = new HashMap<>();
     HashMap<String, String> operandos;
     HashMap<String, String> boolExpr;
     String travaOperandos = null;
}
// Estrutura de um programa    
init
    : buildtags? R_PACKAGE ID R_PT_VIRG imports* programPart+ EOF 
    ;

// Estrutura de um import

imports                
    : R_IMPORTE R_PAR_E import_part (import_part )*  R_PAR_D
    | R_IMPORTE import_part
    ;
import_part
    : ID? T_STRING 
    ;
// Fim do importe -> Ini partes do programa

programPart 
    : dec_const
    | dec_var
    | def_type
    | def_interface
    | def_function
    ;
// Fim partes do programa -> Ini  Declaracao de tipo

def_type
    : R_TIPO ID  ( structType |  type )
    ;
     
def_interface 
    : R_TIPO ID R_INTERFACE R_COL_E func_spec+ R_COL_D 
    ;

func_spec 
    :   ID arguments return_dec
    ;

// Fim Declaracao de tipo -> Ini  

dec_var
    : R_VAR R_PAR_E dec_var_part+ R_PAR_D
    | R_VAR dec_var_part
    ;

dec_var_part
    : id_list (type (R_EQ expression_list)? | R_EQ expression_list)
    ;

dec_var_short
    : id_list R_SHORT_VAR expression_list // Declaracao reconhecendo o tipo do valor atribuido
    ;

id_list
    : ID (R_VIRGULA ID)*
    ;

// Fim Declaracao de variavel -> Ini Operacao de atribuicao

def_assign_op
    : expression_list assign_modify? R_EQ expression_list
    ;

assign_modify
    : R_OP_ADD | R_OP_SUB | R_OP_AST | R_OP_DIV | R_ASSIG_EXTEND | R_ASSIG_COPY
    ;

// Fim Operacao de atribuicao -> Ini  

index
    : R_CHA_E expression R_CHA_D
    ;

arguments
    // expression_list -> chamadas de funcao
    // expression_list_typed -> declaracao de funcao
    : R_PAR_E (expression_list | expression_list_typed  (R_VIRGULA expression_list_typed)*)? R_PAR_D
    ;

expression_list_typed 
    : id_list? type
    ;

// Ini - Constantes   
dec_const
    : R_CONSTANTE dec_const_part
    | R_CONSTANTE R_PAR_E dec_const_part (dec_const_part)* R_PAR_D
    ;
dec_const_part
    : ID type? R_EQ primitive_value
    ;

// Fim - Constantes   -> Ini  Funcoes
def_function
    : R_FUNCTION receive_type? (name=ID)? arguments return_dec? def_block
    ;

return_dec
    : type (R_VIRGULA type)*
    ;

receive_type
    : R_PAR_E ID R_OP_AST? type R_PAR_D   
    ;

// Fim - Funcoes   -> Ini  Switch

def_switch
    : R_SWITCH test R_COL_E def_case+ R_COL_D
    ;


def_case
    : R_CASE expression_list R_COLON statement_list R_BREAK?
    | R_DEFAULT R_COLON statement_list
    ;

statement_list
    : statement+
    ;
// Fim - Switch   -> Ini  Valores

primitive_value
    : T_INTEIRO 
    | (T_BOOL_TRUE | T_BOOL_FALSE) 
    | T_CHAR
    ;

// Fim - Valores   -> Ini  Chamada de funcao

//def_funcao_call locals[String functionName]
//    :ID call_assinature {$functionName = $ID.text; } //funcao
//    ;
// Fim Chamada de funcao -> Ini If

def_if locals[int ltipo]
    : def_if_block (R_ELSE def_if_block)* (R_ELSE def_block)?
    ;

def_if_block
    : R_IF test def_block
    ;

// Fim If -> Ini Lacos

def_for
    : R_FOR ( for_clause | for_each )? def_block // Like for
    ;
for_clause
    : (initialization R_PT_VIRG)? test (R_PT_VIRG increment)?
    ;

initialization
    :base_stmt
    ;

test 
    : expression
    | base_stmt (R_PT_VIRG expression)? 
    ;

increment
    :base_stmt
    ;

for_each
    : primary_expr R_VIRGULA primary_expr ( R_EQ | R_SHORT_VAR) R_RANGE range
    ;

range 
    : expression
    ;
// Fim Lacos -> Ini Retorno de funcao

return_stmt            
    : R_RETURN expression_list?
    ;

//Regra  produz recurssao de parametros em uma funcao.

// Fim Retorno de funcao -> Ini 

expression_list                                                                 
    : expression (R_VIRGULA expression)*
    ;

expression
    //    | expression BINARY_OP expression
    // | expression ('||' | '&&' | '==' | '!=' | '<' | '<=' | '>' | '>=' | '+' | '-' | '|' | '^' | '*' | '/' | '%' | '<<' | '>>' | '&' | '&^') expression
    : R_PAR_E expression R_PAR_D
    | unary_expr
    | expression op=( 
        R_OP_MOD| R_END |
        R_OP_AST | R_OP_DIV| 
        R_OP_ADD | R_OP_SUB ) expression
    
    | expression op=(R_SHIFT_LEFT | R_SHIFT_RIGHT) expression
    | expression op=(R_BIT_AND | R_BIT_XOR | R_BIT_OR) expression
      
    | expression op=(R_COMP_EQ | R_COMP_DIFF |
                     R_COMP_LT | R_COMP_LTE | 
                     R_COMP_GT | R_COMP_GTE) expression
    | expression op=(R_OR | R_AND) expression
    ;

unary_expr
    : op=(R_REFERENCE|R_OP_SUB|R_EXCLAMATION|R_OP_AST) primary_expr
    | primary_expr
    ;

primary_expr returns[String id]
    : operand                               {$id = $operand.Value;}                                                                   //#expr_operando// acesso de um operando
    | literal
    | pe  = primary_expr index              {$id = $pe.id;}                                           //#expr_index// acesso de um index
    | pee = primary_expr expression_seletor {$id = $pee.id;}                                         //#expr_selector// acesso de um atributo
    | pea = primary_expr arguments                {$id = $pea.id;}                    //#expr_arguments// chamada de uma funcao ou metodo
    ;


operand  returns[String Value]
    : ID                {$Value=$ID.text;}
    | primitive_value   {$Value=$primitive_value.text;}
    ;


literal 
    : func_literal
    | composite
    ;

base_stmt 
    :
    | inc_dec 
    | def_assign_op
    | dec_var_short
    | expression
    ;

func_literal
    : R_FUNCTION arguments return_dec? def_block
    ;

composite
    : literalType literal_value
    ;
literalType
    : typename
    | structType
    | arrayType
    ;

structType
    :  R_STRUCT R_COL_E fieldDecl+ R_COL_D 
    ;

fieldDecl
    :(id_list type| anon_field) T_STRING?
    ; 
anon_field 
    : R_OP_AST? typename
    ;
         
arrayType
    : R_CHA_E expression? R_CHA_D typename
    ;

inc_dec 
    : expression op=( R_OP_PP| R_OP_SS)
    ;

literal_value
    : R_COL_E ( (expression_list | element_list) R_VIRGULA )? R_COL_D
    ;

element_list
    : keyed_element (R_VIRGULA keyed_element)*
    ;

keyed_element
    : ID R_COLON expression
    ;

expression_seletor
    : R_PONTO ID
    ;

// Definicao de um bloco de instrucoes
def_block locals[HashMap<String, String> retornos = new HashMap<>();]
    : R_COL_E statement+ R_COL_D
    ;

callExpr:
    | primary_expr arguments
    ;

statement
    : dec_var_short //R_PT_VIRG
    | dec_var //R_PT_VIRG
    | def_assign_op //R_PT_VIRG
    | dec_const 
    | inc_dec
    | primary_expr
    | label_stmt
    //| def_read R_PT_VIRG
    //| def_print R_PT_VIRG
    | return_stmt //R_PT_VIRG     
    //| def_funcao_call R_PT_VIRG
    //| expression //R_PT_VIRG
    | delete //R_PT_VIRG
    | throwStmt
    | fallthroughStmt // dentro de um case do switch avanca para o proximo caso
    | def_if
    | def_for
    | def_switch
    | flux_control
    | try_catch
    ;
// Fim da definicao de um bloco de instrucoes
fallthroughStmt
    : R_FALLTHROUGH
    ;
label_stmt
    : ID R_COLON statement
    ;

throwStmt
    : R_THROW expression R_PT_VIRG
    ;
// Inicio do try cath
try_catch
    : R_TRY def_block 
      catch_exception
      finally_try ?
    ;

catch_exception
    : R_CATCH R_PAR_E dec_var R_PAR_D def_block
    ;

finally_try
    : R_FINALLY def_block
    ;

// Fim do try cath
// Ids de controle de fluxo dentro do codigo
flux_control locals[String control]
    : R_GOTO ID            {$control = $R_GOTO.text;}
    | R_CONTINUE           {$control = $R_CONTINUE.text;}
    | R_BREAK              {$control = $R_BREAK.text;}
    ;

// Definicao de new para alocar enderecos de memoria
newstmt 
    : R_NEW R_PAR_E type (R_VIRGULA T_INTEIRO)? R_PAR_D
    ;

// Definicao de delete para liberar areas de memoria
delete
    : R_DELETE expression( R_VIRGULA expression)?
    ;
// Definicao dos tipos
type returns[String ltype,String keytype,String valuetype]
    : typename          {$ltype = $typename.ltype;}
    | indexedType       {$ltype = $indexedType.ltype;}
    | mapType           {$ltype = "map";}
    ;

indexedType returns[String ltype]
    : typename          {$ltype = $typename.ltype;}
    | index it=indexedType {$ltype = $it.ltype;}
    ;

typename returns[String ltype, Boolean pointer]
    : ID                   {$ltype = $ID.text;}
    | qualifiedId          {$ltype = $qualifiedId.text;}
    | baseType             {$ltype = $baseType.ltype;}
    | R_OP_AST tn=typename {$ltype = $tn.ltype;}
    ;

qualifiedId
    : ID R_PONTO ID
    ;

baseType returns[String ltype]
    : R_INT          {$ltype = $R_INT.text;}
    | R_BOOL         {$ltype = $R_BOOL.text;} 
    | R_CHAR         {$ltype = $R_CHAR.text;}
    | R_STRING       {$ltype = $R_STRING.text;}
    | R_ERROR        {$ltype = $R_ERROR.text;}
    ;


mapType returns[String keytype,String valuetype]
    : R_MAP R_CHA_E k=type R_CHA_D v=type {
                                            $keytype=$k.text;
                                            $valuetype=$v.text;
                                          }
    ;
buildtags 
    : build_stmt+
    ;
build_stmt 
    : R_AT buildtag ID (R_VIRGULA ID)*
    ;
buildtag
    : BUILD_TARGET
    ;

//DEFINICAO DE TOKENS ----------------------------------------------------------
BUILD_TARGET            :'target';
R_BIT_AND               : '&';
R_BIT_XOR               : '^';
R_BIT_OR                : '|';
R_SHIFT_LEFT            : '<<';
R_SHIFT_RIGHT           : '>>';
R_AT                    : '@';    
R_DBL_SLASH             : '//';
R_REFERENCE             : '&';
R_INTERFACE             : 'interface';
R_RANGE                 : 'range';
R_STRUCT                : 'struct';
R_OP_MOD                : '%';
R_VAR                   : 'var';
R_SHORT_VAR             : ':=';
R_GOTO                  : 'goto';
R_FALLTHROUGH           : 'fallthrough';
R_MAP                   : 'map';
R_ERROR                 : 'error';
R_NEW                   : 'new';
R_DELETE                : 'delete';
R_TRY                   : 'try';
R_CATCH                 : 'catch';
R_FINALLY               : 'finally';
R_DEFAULT               : 'default';
//R_PRINT                 : 'print';
//R_READ                  : 'read';
R_IMPORTE               : 'import';
//R_INIT_LIBRARY          : 'library';
R_PACKAGE               : 'package';
//R_THREAD                : 'thread';
R_TRAP                  : 'trap';
R_INT                   : 'int';
R_CHAR                  : 'char';
R_BOOL                  : 'bool';
R_STRING                : 'string';
//R_OBJECT                : 'object';
//R_ARRAY                 : 'array';
//R_EXCEPTION             : 'Exception';
R_TIPO                  : 'type';
R_FUNCTION              : 'func';
//R_METHOD                : 'method';ARO
R_CONSTANTE             : 'const';
R_IN                    : 'in';
R_SWITCH                : 'switch';
R_CASE                  : 'case';
R_FOR                   : 'for';
R_RETURN                : 'return';
R_CONTINUE              : 'continue';
R_BREAK                 : 'break';
R_THROW                 : 'throw';
R_ELSE                  : 'else';
R_IF                    : 'if';
//R_ASYNC                 : 'async';
//T_TRAP_SYNC             : 'SYNC';
//T_TRAP_EXEC             : 'EXEC';
//T_TRAP_SYNEXEC          : 'SYNEXEC';
//T_TRAP_SEND             : 'SEND';
//T_TRAP_RECEIVE          : 'RECEIVE';
R_EXCLAMATION           : '!';
R_PT_VIRG               : ';';
R_PAR_E                 : '(';
R_PAR_D                 : ')';
R_COL_E                 : '{';
R_COL_D                 : '}';
R_CHA_E                 : '[';
R_CHA_D                 : ']';
R_EQ                    : '=';
R_VIRGULA               : ',';
R_PONTO                 : '.';
R_COLON                 : ':';
R_END                   : '&' ;

R_AND                   : '&&' ;
R_OR                    : '||';
//Comparison
R_COMP_EQ               : '==' ;
R_COMP_DIFF             : '!=';
R_COMP_LTE              : '<=' ;
R_COMP_LT               : '<' ;
R_COMP_GTE              : '>=' ;
R_COMP_GT               : '>' ;
//assing
R_ASSIG_EXTEND          : '::';
R_ASSIG_COPY            : ':';
//arithmetic
R_OP_DIV                : '/';
R_OP_ADD                : '+';
R_OP_SUB                : '-';
R_OP_AST                : '*';
R_OP_NEG                : '!';
R_OP_SS                 : '--';
R_OP_PP                 : '++';
R_UND                   : '_';
R_INTERROGATION         : '?';

T_CHAR                  : '\'' .? '\'' ;
T_STRING                : '"' .*? '"' ;
T_BOOL_TRUE             : 'true';              
T_BOOL_FALSE            : 'false' ;              
T_NULL                  : 'nil'; 

ID                      : LETTER ( LETTER | DIGITO )*;
T_INTEIRO               : DIGITO+ ;

fragment    LETTER      : ('a'..'z' | 'A'..'Z' | '_') ;
fragment    DIGITO      : '0'..'9' ;

//ID                      : CHARACTER ( CHARACTER | DIGITO )* ;
//fragment    CHARACTER   : [_a-zA-Z]
//                        ;

R_LINE_COMMENT          : '//' .*? '\r'? '\n' -> skip ;  // Match "#" stuff '\n'
R_WS                    : (' '|'\t'|'\r'|'\n')+ -> skip ;
R_COMMENT               : '/*' .*? '*/' -> skip ; // Match "/*" stuff "*/"


/*
/*
: ID literal_value                                                             #expr_literal
 | R_REFERENCE expression                                                       #expr_pointer
 | R_PAR_E expression R_PAR_D                                                   #expr_par
 | expression (R_PT_VIRG expression)                                            #expr_chain_operacoes
 | expression op=(R_OP_AST | R_OP_DIV) expression                               #expr_arit_md
 | expression op=(R_OP_ADD | R_OP_SUB) expression                               #expr_arit_as
 | expression op=(R_COMP_LT | R_COMP_GT | R_COMP_LTE | R_COMP_GTE) expression   #expr_comp_lt
 | expression op=(R_COMP_DIFF | R_COMP_EQ) expression                           #expr_comp_eqd
 | expression R_AND expression                                                  #expr_and
 | expression R_OR expression                                                   #expr_or
 | expression primitive_value                                                   #expr_primitive_value
 | expression ( R_OP_PP| R_OP_SS)                                               #expr_inc_dec
 | R_OP_SUB expression                                                          #expr_negative
 | R_PAR_E type R_PAR_D expression                                              #expr_assertion
 | R_EXCLAMATION expression                                                     #expr_neg_bool
 | expression R_INTERROGATION expression R_COLON expression                     #expr_ternary
 | def_function                                                                 #expr_def_function
 | newstmt                                                                      #expr_allocation
 | ID                                                                           #expr_id
 ;

inc_dec_stmt
    : 
    ;

def_object 
    : R_COL_E (object_prop ( R_VIRGULA object_prop )*)? R_COL_D
    ;

object_prop returns[String id]
    : ID R_COLON expression {$id = $ID.text;}
    ;


address_access_dst
    : ID indices? access_prop ?
    ;

access_prop
    : (R_PONTO ID indices?) access_prop ? 
    ;

address_access_src
    : ID indices? call_assinature? access_prop_src?
    ;
access_prop_src
    : (R_PONTO ID indices? call_assinature?) access_prop_src?
    ;
address
    : R_REFERENCE T_INTEIRO 
    ;

//| R_THREAD    R_OP_AST*   {$ltype = $R_THREAD.text;}
    //| R_FUNCTION  R_OP_AST*   {$ltype = $R_FUNCTION.text;}
    //| R_EXCEPTION R_OP_AST*   {$ltype = $R_EXCEPTION.text;}
  
    //| def_method
    //| dec_trap
    //| dec_thread
    //| main

call_from_return
    : (call_assinature | indices | access_prop_src) call_from_return ?
    ;
 
boolena_operator
    : R_COMP_EQ | R_COMP_DIFF | R_COMP_LTE | R_COMP_GTE | R_COMP_LT | R_COMP_GT
    ;

value
    : expression                #expressionValue
    //| def_array                 #arrayValue
    | def_object                #objectValue
    | address                   #pureAddressValue
    ;

def_array
    : R_CHA_E ( value ( R_VIRGULA value )* )?  R_CHA_D
    ;

gen_list
    : def_array
    | address_access_src
    | def_funcao_call
    ;

def_print
    : R_PRINT R_PAR_E list_values R_PAR_D
    ;

def_read
    : R_READ R_PAR_E list_vars R_PAR_D
    ;
list_vars
    : address_access_src (R_VIRGULA address_access_src)*
    ;


param_list_dec         
    : dec_var (R_PT_VIRG dec_var)*
    ;
main 
    : R_FUNCTION R_MAIN R_PAR_E param_list_dec? R_PAR_D R_COLON return_list def_block
    ;
dec_thread 
    : R_IN ID R_PAR_E param_list_dec? R_PAR_D def_block
    ;

dec_trap locals[String label]
    : R_TRAP name=trap_id  R_PAR_E param_list_dec? R_PAR_D def_block {$label = $name.text;}
    ;

trap_id
    : (T_TRAP_SYNC |T_TRAP_EXEC |T_TRAP_SYNEXEC |T_TRAP_SEND |T_TRAP_RECEIVE) 
    ;

*/