#include "fullfomsubref.h"


void shiftstore (int i) {
    for (int j = 0; j < _store.size(); j++)
         _store[j] = termShift(i, _store[j]);
}



antlrcpp::Any evalBind::visitToplevel(fullfomsubrefParser::ToplevelContext *ctx) {    
    for (int i = 0; i < ctx->command().size(); i++)         
        visit(ctx->command(i));
    return 1;
}


antlrcpp::Any evalBind::visitC_term(fullfomsubrefParser::C_termContext *ctx){
    bool NoRuleApplies0 = false;
    bool ErrorEncountered0 = false;         
    Term* t = visit(ctx->term());
    Ty* ty = typeOf(t);
    t = eval(t, &NoRuleApplies0, &ErrorEncountered0);    
    cout << t->getTerm_str() + " :"+ ty->getTy_str() + ";" << endl;
    return t;
}


antlrcpp::Any evalBind::visitC_var_ty(fullfomsubrefParser::C_var_tyContext *ctx){                
    Ty* ty = visit(ctx->ty());
    Binding* bind = new Binding(VarBind, ty);         
    bind = checkbinding(bind);
    bind =  evalbinding(bind);
    cout << ctx->var()->getText() << " " << bind->getBing_str() << ";" << endl;     
    _context.push_back(pair_sb(ctx->var()->getText(), bind)); 
    shiftstore(1);   
    return bind;
}


antlrcpp::Any evalBind::visitC_var_term(fullfomsubrefParser::C_var_termContext *ctx) {        
    Term* t = visit(ctx->term());
    Binding* bind = new Binding(TmAbbBind, t, new Ty(TyNone));         
    bind = checkbinding(bind);
    bind =  evalbinding(bind);
    cout << ctx->var()->getText() << " " << bind->getBing_str() << ";" << endl;     
    _context.push_back(pair_sb(ctx->var()->getText(), bind)); 
    shiftstore(1);   
    return bind;   
}


antlrcpp::Any evalBind::visitC_u_var(fullfomsubrefParser::C_u_varContext *ctx) { 
    Binding* bind = new Binding(TyVarBind, new Ty(TyTop));
    _context.push_back(pair_sb(ctx->u_var()->getText(), bind));
    bind = checkbinding(bind);    
    bind =  evalbinding(bind);
    cout << ctx->u_var()->getText() << " " << bind->getBing_str() << ";" << endl; 
    _context.push_back(pair_sb(ctx->u_var()->getText(), bind));
    shiftstore(1);        
    return bind;
}



antlrcpp::Any evalBind::visitC_u_var_kind(fullfomsubrefParser::C_u_var_kindContext *ctx) { 
    Binding* bind = new Binding(TyVarBind, maketop(visit(ctx->kind())));
    _context.push_back(pair_sb(ctx->u_var()->getText(), bind));
    bind = checkbinding(bind);    
    bind =  evalbinding(bind);
    cout << ctx->u_var()->getText() << " " << bind->getBing_str() << ";" << endl; 
    _context.push_back(pair_sb(ctx->u_var()->getText(), bind));
    shiftstore(1);         
    return bind;
}


Ty* evalBind::addbinders(fullfomsubrefParser::C_tyabbContext *ctx, int depth) {
    Kind* kn;
    Ty *ty, *result_ty;
    Binding* bind;
    
    if (depth > 0){
        bind = new Binding(NameBind);
        _context.push_back(pair_sb(ctx->tyabbargs(ctx->tyabbargs().size() - depth)->u_var()->getText(), bind));        
        if(ctx->tyabbargs(ctx->tyabbargs().size() - depth)->okind()){
            kn = visit(ctx->tyabbargs(ctx->tyabbargs().size() - depth)->okind()->kind());
            result_ty = new Ty(TyAbs, ctx->tyabbargs(ctx->tyabbargs().size() - depth)->u_var()->getText(), kn, addbinders(ctx, depth-1));
        }
        else
            result_ty = new Ty(TyAbs, ctx->tyabbargs(ctx->tyabbargs().size() - depth)->u_var()->getText(), new Kind(KnStar), addbinders(ctx, depth-1));        
        _context.pop_back();
    }
    else
        result_ty = visit(ctx->ty());
    return result_ty;
}


antlrcpp::Any evalBind::visitC_tyabb(fullfomsubrefParser::C_tyabbContext *ctx) {
    Binding* bind = new Binding(TyAbbBind, addbinders(ctx, ctx->tyabbargs().size()), new Kind(KnNone)); 
    bind = checkbinding(bind);    
    bind =  evalbinding(bind);
    cout << ctx->u_var()->getText() << " " << bind->getBing_str() << ";" << endl; 
    _context.push_back(pair_sb(ctx->u_var()->getText(), bind));
    shiftstore(1);      
    return bind;
}


antlrcpp::Any evalBind::visitC_somebind(fullfomsubrefParser::C_somebindContext *ctx) {
    Binding *b1, *b2;
    Term* t0;
    Term* t = visit(ctx->term()); 
    Ty* ty =  lcst(typeOf(t));
    cout << ty->getTy_str() << endl;
    bool NoRuleApplies0 = false;
    bool ErrorEncountered0 = false;    
    if (ty->_typ == TySome){
        t0 = eval(t, &NoRuleApplies0, &ErrorEncountered0);
        if (t0->_t_name == TmPack)
            b2 = new Binding(TmAbbBind, termShift(1, t0->_term0), ty->_ty1); 
        else
            b2 = new Binding(VarBind, ty->_ty1);         
        b1 = new Binding(TyVarBind, ty->_ty0);
        _context.push_back(pair_sb(ctx->u_var()->getText(), b1));
        cout << ctx->var()->getText() << " :" << ty->_ty1->getTy_str() << ";" << endl; 
        _context.push_back(pair_sb(ctx->var()->getText(), b2));
    }
    else {
        showErrorMsg(t, "existential type expected");
        exit(1);
    }
    return b2;
}


antlrcpp::Any evalBind::visitKind(fullfomsubrefParser::KindContext *ctx) {
    return visit(ctx->arrowkind());
}


antlrcpp::Any evalBind::visitArrkind_arr(fullfomsubrefParser::Arrkind_arrContext *ctx) {
    return new Kind(KnArr, (Kind*) visit(ctx->akind()), (Kind*)visit(ctx->arrowkind()));
}


antlrcpp::Any evalBind::visitArrkind_akind(fullfomsubrefParser::Arrkind_akindContext *ctx) {
    return visit(ctx->akind());;
}



antlrcpp::Any evalBind::visitAsct_as(fullfomsubrefParser::Asct_asContext *ctx) { 
    return new Term(TmAscribe, pickInfo(ctx), (Term*) visit(ctx->aterm()), (Ty*) visit(ctx->ty()));
 }


antlrcpp::Any evalBind::visitAsct_aterm(fullfomsubrefParser::Asct_atermContext *ctx) {
    return visit(ctx->aterm());
}


antlrcpp::Any evalBind::visitOty_leqty(fullfomsubrefParser::Oty_leqtyContext *ctx) {
    return visit(ctx->ty());
}



antlrcpp::Any evalBind::visitOty_maketop(fullfomsubrefParser::Oty_maketopContext *ctx) {
    return maketop(visit(ctx->kind()));
}



antlrcpp::Any evalBind::visitP_proj_int(fullfomsubrefParser::P_proj_intContext *ctx){
    return new Term(TmProj, pickInfo(ctx), (Term*) visit(ctx->pathterm()), ctx->INT()->getText());
}


antlrcpp::Any evalBind::visitP_proj_var(fullfomsubrefParser::P_proj_varContext *ctx){
    return new Term(TmProj, pickInfo(ctx), (Term*) visit(ctx->pathterm()), ctx->var()->getText());
}


antlrcpp::Any evalBind::visitP_ascribeterm(fullfomsubrefParser::P_ascribetermContext *ctx) {
    return visit(ctx->ascribeterm());
}


antlrcpp::Any evalBind::visitT_var(fullfomsubrefParser::T_varContext *ctx) {
     return visit(ctx->var());
}
    

antlrcpp::Any evalBind::visitT_abs(fullfomsubrefParser::T_absContext *ctx) {
    Ty* ty = visit(ctx->ty());
    Binding* bind = new Binding(NameBind);
    _context.push_back(pair_sb(ctx->var()->getText(), bind));  
    Term* t = visit(ctx->term());
    Term* result_t = new Term(TmAbs, pickInfo(ctx), ctx->var()->getText(), ty, t);
    _context.pop_back();
    return result_t;
}


antlrcpp::Any evalBind::visitT_us_abs(fullfomsubrefParser::T_us_absContext *ctx) {
    Ty* ty = visit(ctx->ty());
    Binding* bind = new Binding(NameBind);
    _context.push_back(pair_sb("_", bind));  
    Term* t = visit(ctx->term());
    Term* result_t = new Term(TmAbs, pickInfo(ctx), "_", ty, t);
    _context.pop_back();
    return result_t;
}


antlrcpp::Any evalBind::visitT_tabs(fullfomsubrefParser::T_tabsContext *ctx) {
    Ty* ty;
    if (ctx->oty())
        ty = visit(ctx->oty());
    else
        ty = new Ty(TyTop);
    Binding* bind = new Binding(NameBind);
    _context.push_back(pair_sb(ctx->u_var()->getText(), bind));
    Term* t = visit(ctx->term());
    Term* result_t = new Term(TmTAbs, pickInfo(ctx), ctx->u_var()->getText(), ty, t);
    _context.pop_back();
    return result_t;

    
}


antlrcpp::Any evalBind::visitT_assign(fullfomsubrefParser::T_assignContext *ctx) {
    return new Term(TmAssign, pickInfo(ctx), (Term*) visit(ctx->appterm(0)), (Term*) visit(ctx->appterm(1)));;
}


antlrcpp::Any evalBind::visitT_letrec(fullfomsubrefParser::T_letrecContext *ctx) {
    Ty* ty = visit(ctx->ty());
    Binding* bind = new Binding(NameBind);
    _context.push_back(pair_sb(ctx->var()->getText(), bind));    
    Term* t = visit(ctx->term(0));
    Term* in_t = visit(ctx->term(1)); 
    _context.pop_back();
    Term* abs_t = new Term(TmAbs, pickInfo(ctx), ctx->var()->getText(), ty, t);    
    Term* fix_t = new Term(TmFix, pickInfo(ctx), abs_t);      
    Term* result_t = new Term(TmLet, pickInfo(ctx), ctx->var()->getText(), fix_t, in_t);
    return result_t;    
}


antlrcpp::Any evalBind::visitT_case_of(fullfomsubrefParser::T_case_ofContext *ctx) {
     return new Term(TmCase, pickInfo(ctx), (Term*) visit(ctx->term()), (Ccases*) visit(ctx->ccases()));
}


antlrcpp::Any evalBind::visitCcases(fullfomsubrefParser::CcasesContext *ctx){
    Ccases* ccs = new Ccases();
    Ccase* cc;
    for (int i = 0; i < ctx->ccase().size(); i++){
        cc= visit(ctx->ccase(i));
        ccs->push_back(cc);        
    }
    return ccs;
}


antlrcpp::Any evalBind::visitCcase(fullfomsubrefParser::CcaseContext *ctx){
    Binding* bind = new Binding(NameBind);
    _context.push_back(pair_sb(ctx->var(1)->getText(), bind));
    Ccase* cc = new Ccase(ctx->var(0)->getText(), ctx->var(1)->getText(), visit(ctx->appterm()));
    _context.pop_back();
    return cc;
}


antlrcpp::Any evalBind::visitT_pathterm(fullfomsubrefParser::T_pathtermContext *ctx) {
    return visit(ctx->pathterm());    
}


antlrcpp::Any evalBind::visitT_timesfloat(fullfomsubrefParser::T_timesfloatContext *ctx) {
    return new Term(TmTimesfloat, pickInfo(ctx), (Term*) visit(ctx->pathterm(0)), (Term*) visit(ctx->pathterm(1)));    
}


antlrcpp::Any evalBind::visitT_appterm(fullfomsubrefParser::T_apptermContext *ctx) {
    return visit(ctx->appterm());
}


antlrcpp::Any evalBind::visitT_fix(fullfomsubrefParser::T_fixContext *ctx) {
    return new Term(TmFix, pickInfo(ctx), (Term*) visit(ctx->pathterm()));
}


antlrcpp::Any evalBind::visitT_ref(fullfomsubrefParser::T_refContext *ctx) {
    return new Term(TmRef, pickInfo(ctx), (Term*) visit(ctx->pathterm()));
}


antlrcpp::Any evalBind::visitT_deref(fullfomsubrefParser::T_derefContext *ctx) {
    return new Term(TmDeref, pickInfo(ctx), (Term*) visit(ctx->pathterm()));
}


antlrcpp::Any evalBind::visitT_paren(fullfomsubrefParser::T_parenContext *ctx) {
    return visit(ctx->termseq());
}


antlrcpp::Any evalBind::visitT_app(fullfomsubrefParser::T_appContext *ctx) {
    Term* t0 = visit(ctx->appterm());
    Term* t1 = visit(ctx->pathterm());
    return new Term(TmApp, pickInfo(ctx), t0, t1);
}


antlrcpp::Any evalBind::visitT_tapp(fullfomsubrefParser::T_tappContext *ctx) {
    return new Term(TmTApp, pickInfo(ctx), (Term*) visit(ctx->appterm()), (Ty*) visit(ctx->ty()));
}


antlrcpp::Any evalBind::visitT_unpack(fullfomsubrefParser::T_unpackContext *ctx) {
    Term* t0 = visit(ctx->term(0)); 
    Binding* bind0 = new Binding(NameBind);
    _context.push_back(pair_sb(ctx->u_var()->getText(), bind0));     
    Binding* bind1 = new Binding(NameBind);
    _context.push_back(pair_sb(ctx->var()->getText(), bind1));        
    Term* t1 = visit(ctx->term(1));
    Term* result_t = new Term(TmUnpack, pickInfo(ctx), ctx->u_var()->getText(), ctx->var()->getText(), t0, t1);
    _context.pop_back();
    _context.pop_back();
    return result_t;
}


antlrcpp::Any evalBind::visitT_if(fullfomsubrefParser::T_ifContext *ctx) {
    Term* t0 = visit(ctx->term(0));
    Term* t1 = visit(ctx->term(1));
    Term* t2 = visit(ctx->term(2));
    return new Term(TmIf, pickInfo(ctx), t0, t1, t2);
}


antlrcpp::Any evalBind::visitT_let(fullfomsubrefParser::T_letContext *ctx) {
    Term* t0 = visit(ctx->term(0));
    Binding* bind = new Binding(NameBind);
    _context.push_back(pair_sb(ctx->var()->getText(), bind));    
    Term* t1 = visit(ctx->term(1));
    Term* result_t = new Term(TmLet, pickInfo(ctx), ctx->var()->getText(), t0, t1);
    _context.pop_back();
    return result_t;
}


antlrcpp::Any evalBind::visitT_us_let(fullfomsubrefParser::T_us_letContext *ctx) {
    Term* t0 = visit(ctx->term(0));
    Binding* bind = new Binding(NameBind);
    _context.push_back(pair_sb("_", bind)); 
    Term* t1 = visit(ctx->term(1));
    Term* result_t = new Term(TmLet, pickInfo(ctx), "_", t0, t1);
    _context.pop_back();
    return result_t;
}


antlrcpp::Any evalBind::visitT_error(fullfomsubrefParser::T_errorContext *ctx) {
     return new Term(TmError, pickInfo(ctx));
}


antlrcpp::Any evalBind::visitT_try(fullfomsubrefParser::T_tryContext *ctx){
    return new Term(TmTry, pickInfo(ctx), (Term*) visit(ctx->term(0)), (Term*) visit(ctx->term(1)));
}


antlrcpp::Any evalBind::visitVar(fullfomsubrefParser::VarContext *ctx) {
    return new Term(TmVar, pickInfo(ctx), name2index(ctx->getText()));
} 


antlrcpp::Any evalBind::visitU_var(fullfomsubrefParser::U_varContext *ctx) {      
    return new Ty(TyVar, name2index(ctx->getText()));
}


antlrcpp::Any evalBind::visitFields(fullfomsubrefParser::FieldsContext *ctx) {
    Fields* fs = new Fields();
    Field* f;
    for (int i = 0; i < ctx->field().size(); i++){
        f = visit(ctx->field(i));
        if (f->_label == "")
            f->_label = to_string(i + 1);
        fs->push_back(f); 
    }     
    return new Term(TmRecord, pickInfo(ctx), fs);   
}


antlrcpp::Any evalBind::visitT_record(fullfomsubrefParser::T_recordContext *ctx){
    Term* result_t;
    if (ctx->fields())
        result_t =visit(ctx->fields());
    else
        result_t = new Term(TmRecord, pickInfo(ctx), new Fields());
    return result_t;
}


antlrcpp::Any evalBind::visitT_unit(fullfomsubrefParser::T_unitContext *ctx) {
    return new Term(TmUnit, pickInfo(ctx));
}


antlrcpp::Any evalBind::visitT_string(fullfomsubrefParser::T_stringContext *ctx) {
    return new Term(TmString, pickInfo(ctx), ctx->STRINGV()->getText());
}


antlrcpp::Any evalBind::visitT_pack(fullfomsubrefParser::T_packContext *ctx) {
    return new Term(TmPack, pickInfo(ctx), (Ty*) visit(ctx->ty(0)), (Term*) visit(ctx->term()), (Ty*) visit(ctx->ty(1)));
}


antlrcpp::Any evalBind::visitT_true(fullfomsubrefParser::T_trueContext *ctx) {
    return new Term(TmTrue, pickInfo(ctx));
}


antlrcpp::Any evalBind::visitT_false(fullfomsubrefParser::T_falseContext *ctx) {
    return new Term(TmFalse, pickInfo(ctx));
}


antlrcpp::Any evalBind::visitT_tag(fullfomsubrefParser::T_tagContext *ctx) {
    Term* result_t = new Term(TmTag, pickInfo(ctx), ctx->var()->getText(), (Term*) visit(ctx->term()), (Ty*) visit(ctx->ty()));
    return result_t;
}


antlrcpp::Any evalBind::visitTy_arrowty(fullfomsubrefParser::Ty_arrowtyContext *ctx) {
    return visit(ctx->arrowty());
}


antlrcpp::Any evalBind::visitTy_abs(fullfomsubrefParser::Ty_absContext *ctx) {
    Ty* result_ty;
    Kind* kn;
    if (ctx->okind())
        kn = visit(ctx->okind());
    else
        kn = new Kind(KnStar);
    Binding* bind = new Binding(NameBind);
    _context.push_back(pair_sb(ctx->u_var()->getText(), bind));
    result_ty = new Ty(TyAbs, ctx->u_var()->getText(), kn, (Ty*) visit(ctx->ty()));
    _context.pop_back();
    return result_ty;
}


antlrcpp::Any evalBind::visitTy_all(fullfomsubrefParser::Ty_allContext *ctx) {
    Ty* ty;
    if (ctx->oty())
        ty = visit(ctx->oty());
    else
        ty = new Ty(TyTop);
    Binding* bind = new Binding(NameBind);
    _context.push_back(pair_sb(ctx->u_var()->getText(), bind));
    Ty* result_ty = new Ty(TyAll, ctx->u_var()->getText(), ty, (Ty*) visit(ctx->ty()));
    _context.pop_back();
    return result_ty;
}

antlrcpp::Any evalBind::visitTy_ref(fullfomsubrefParser::Ty_refContext *ctx) {        
    return new Ty(TyRef, (Ty*) visit(ctx->aty()));
}


antlrcpp::Any evalBind::visitTy_source(fullfomsubrefParser::Ty_sourceContext *ctx) {
    return new Ty(TySource, (Ty*) visit(ctx->aty()));
}


antlrcpp::Any evalBind::visitTy_sink(fullfomsubrefParser::Ty_sinkContext *ctx) {
    return new Ty(TySink, (Ty*) visit(ctx->aty()));
}

antlrcpp::Any evalBind::visitAty_paren(fullfomsubrefParser::Aty_parenContext *ctx) {
    return visit(ctx->ty());
}


antlrcpp::Any evalBind::visitAty_unit(fullfomsubrefParser::Aty_unitContext *ctx) {
    return new Ty(TyUnit);
}


antlrcpp::Any evalBind::visitAty_float(fullfomsubrefParser::Aty_floatContext *ctx) {
    return new Ty(TyFloat);
}


antlrcpp::Any evalBind::visitAty_bool(fullfomsubrefParser::Aty_boolContext *ctx) {
    return new Ty(TyBool);
}


antlrcpp::Any evalBind::visitAty_u_var(fullfomsubrefParser::Aty_u_varContext *ctx) {
    Ty* result_ty;
    if(isnamebound(ctx->getText()))
        result_ty =  new Ty(TyVar, name2index(ctx->getText()));
    else
        result_ty = new  Ty(TyId, ctx->getText());
    return result_ty;
}


antlrcpp::Any evalBind::visitAty_top(fullfomsubrefParser::Aty_topContext *ctx) {
    return new Ty(TyTop);
}


antlrcpp::Any evalBind::visitAty_bot(fullfomsubrefParser::Aty_botContext *ctx) {
    return new Ty(TyBot);
}


antlrcpp::Any evalBind::visitAty_some(fullfomsubrefParser::Aty_someContext *ctx) {
    Ty* ty;
    if (ctx->oty())
        ty = visit(ctx->oty());
    else
        ty = new Ty(TyTop);
    Binding* bind = new Binding(NameBind);
    _context.push_back(pair_sb(ctx->u_var()->getText(), bind));
    Ty* result_ty = new Ty(TySome, ctx->u_var()->getText(), ty, (Ty*) visit(ctx->ty()));
    _context.pop_back();
    return result_ty;

}

antlrcpp::Any evalBind::visitAty_string(fullfomsubrefParser::Aty_stringContext *ctx) {
    return new Ty(TyString);
}


antlrcpp::Any evalBind::visitAty_nat(fullfomsubrefParser::Aty_natContext *ctx) {
    return new Ty(TyNat);
}


antlrcpp::Any evalBind::visitT_pred(fullfomsubrefParser::T_predContext *ctx){
    return new Term(TmPred, pickInfo(ctx), (Term*) visit(ctx->appterm()));
}


antlrcpp::Any evalBind::visitT_succ(fullfomsubrefParser::T_succContext *ctx){
    return new Term(TmSucc, pickInfo(ctx), (Term*) visit(ctx->appterm()));
}


antlrcpp::Any evalBind::visitT_iszero(fullfomsubrefParser::T_iszeroContext *ctx){
    return new Term(TmIsZero, pickInfo(ctx), (Term*) visit(ctx->appterm()));
}

 
antlrcpp::Any evalBind::visitAkind_star(fullfomsubrefParser::Akind_starContext *ctx) {
    return new Kind(KnStar);
}

antlrcpp::Any evalBind::visitAkind_paren(fullfomsubrefParser::Akind_parenContext *ctx) {
    return visit(ctx->kind());
}

antlrcpp::Any evalBind::visitOkind(fullfomsubrefParser::OkindContext *ctx) {
    return visit(ctx->kind());
}

antlrcpp::Any evalBind::visitAppty_app(fullfomsubrefParser::Appty_appContext *ctx){
    return new Ty(TyApp, (Ty*) visit(ctx->appty()), (Ty*) visit(ctx->aty()));
}

antlrcpp::Any evalBind::visitAppty_aty(fullfomsubrefParser::Appty_atyContext *ctx){
    return visit(ctx->aty());
}


antlrcpp::Any evalBind::visitTyabbargs(fullfomsubrefParser::TyabbargsContext *ctx) {
    cout<< " Nobody visits 'visitTyabbargs'" << endl;
    return 1;
}


antlrcpp::Any evalBind::visitTs_term(fullfomsubrefParser::Ts_termContext *ctx) {
    return visit(ctx->term());    
}
 

antlrcpp::Any evalBind::visitTs_term_tseq(fullfomsubrefParser::Ts_term_tseqContext *ctx) {
    Term* t = visit(ctx->term());
    Binding* binding = new Binding(NameBind);
    _context.push_back(pair_sb("_", binding));   
    Term* t1 = visit(ctx->termseq());
     _context.pop_back();      
    return new Term(TmApp, pickInfo(ctx), new Term(TmAbs, pickInfo(ctx), "_", new Ty(TyUnit), t1), t);   
}


Term* evalBind::int2term(ParserRuleContext* ctx, int n) {
    Term* result_t;
    if (n == 0)
        result_t = new Term(TmZero, pickInfo(ctx));
    else
        result_t = new Term(TmSucc, pickInfo(ctx), int2term(ctx, n-1));
    return result_t;
}


antlrcpp::Any evalBind::visitT_inert(fullfomsubrefParser::T_inertContext *ctx) {
    return new Term(TmInert, pickInfo(ctx), (Ty*) visit(ctx->ty()));
}


antlrcpp::Any evalBind::visitT_int(fullfomsubrefParser::T_intContext *ctx) {
    return int2term(ctx, stoi(ctx->getText()));
}


antlrcpp::Any evalBind::visitT_float(fullfomsubrefParser::T_floatContext *ctx) {    
    return new Term(TmFloat, pickInfo(ctx), ctx->getText());
}


antlrcpp::Any evalBind::visitF_var_term(fullfomsubrefParser::F_var_termContext *ctx) {
    return new Field(ctx->var()->getText(), visit(ctx->term()));
}


antlrcpp::Any evalBind::visitF_term(fullfomsubrefParser::F_termContext *ctx) {
    return new Field("", visit(ctx->term()));
}


antlrcpp::Any evalBind::visitArrty_arr(fullfomsubrefParser::Arrty_arrContext *ctx) {
    return new Ty(TyArr, (Ty*) visit(ctx->appty()), (Ty*) visit(ctx->arrowty()));
}

antlrcpp::Any evalBind::visitArrty_appty(fullfomsubrefParser::Arrty_apptyContext *ctx) {
    return visit(ctx->appty());
}


antlrcpp::Any evalBind::visitAty_variant(fullfomsubrefParser::Aty_variantContext *ctx) {
    Ty* result_ty;
    if (ctx->fieldtys())
        result_ty = new Ty(TyVariant, (FieldTys*) visit(ctx->fieldtys()));
    else
        result_ty = new Ty(TyVariant, new FieldTys());
    return result_ty;
}

antlrcpp::Any evalBind::visitAty_record(fullfomsubrefParser::Aty_recordContext *ctx) {
    Ty* result_ty;
    if (ctx->fieldtys())
        result_ty = new Ty(TyRecord, (FieldTys*) visit(ctx->fieldtys()));
    else
        result_ty = new Ty(TyRecord, new FieldTys());
    return result_ty;
}


antlrcpp::Any evalBind::visitFieldtys(fullfomsubrefParser::FieldtysContext *ctx) {
    FieldTys* tys = new FieldTys();
    FieldTy* fty;
    for (int i = 0; i < ctx->fieldty().size(); i++){
        fty = visit(ctx->fieldty(i));
        if (fty->_label == "")
            fty->_label = to_string(i + 1);
        tys->push_back(fty);        
    }
    return tys;
}


antlrcpp::Any evalBind::visitFty_var_ty(fullfomsubrefParser::Fty_var_tyContext *ctx) {
    return new FieldTy(ctx->var()->getText(), visit(ctx->ty()));
}


antlrcpp::Any evalBind::visitFty_ty(fullfomsubrefParser::Fty_tyContext *ctx) {
    return new FieldTy("", visit(ctx->ty()));
}


/*------------------ pick information -----------------------*/

string evalBind::pickInfo(ParserRuleContext* ctx) {
    int line, pos;
    line = ctx->getStart()->getLine();
    pos = ctx->getStart()->getCharPositionInLine();
    string info = _filename + ":" + to_string(line) + ":" + to_string(pos);
    return info;
}  
