/*
 * 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.
 */
package grammar.visitorAndWalkers;

import API.Functions;
import API.Imports;
import API.Instruction;
import API.Interfaces;
import API.Tipos;
import API.Utils;
import API.Variaveis;
import ast.AbstractSyntaxTree;
import ast.Node;
import common.Log;
import compiler.IvannosysCompiler;
import grammar.IvannosysGrammarBaseListener;
import grammar.IvannosysGrammarParser;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.RuleContext;
import org.antlr.v4.runtime.tree.TerminalNode;

/**
 *
 * @author Eugenio
 */
public class IvannosysListener extends IvannosysGrammarBaseListener {

    protected int uniq = 0;
    protected int InsideType;
    protected boolean insideSwitch = false;
//    protected String packageName;
    protected Log errors;
    protected AbstractSyntaxTree ast;
    protected IvannosysCompiler compiler;
    protected Stack<String> scopeStack = new Stack<>();
    protected Stack<String> scopeFile = new Stack<>();
    protected LinkedList<Boolean> ReadId = new LinkedList<>();
    protected HashMap<String, String> packages = new HashMap<>();
    protected LinkedList<String> TypePath;
//    protected final ArrayList<String> paths;
//    protected boolean returnReferece;
//    protected int paramPosition;
//    protected int defAtribuicaoIndex;
//    protected int returnPosition;
    protected LinkedList<String> packageNames = new LinkedList<>();

    public IvannosysListener(IvannosysCompiler comp) throws Exception {
        ast = AbstractSyntaxTree.getAbstractSyntaxTree();
        compiler = comp;
        errors = new Log();
        this.ReadId.push(true);
    }

    public Log Error() {
        return errors;
    }

    @Override
    public void enterBuild_stmt(IvannosysGrammarParser.Build_stmtContext ctx) {
        String tag = ctx.buildtag().getText();
        ArrayList<String> values = new ArrayList<>();
        for (TerminalNode id : ctx.ID()) {
            values.add(id.getText());
        }
        ast.getCompileParams().addList(tag, values);
        super.enterBuild_stmt(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    //INIT
    @Override

    public void enterInit(IvannosysGrammarParser.InitContext ctx) {
        packageNames.push(ctx.ID().getText());

        String scope = packageNames.peek();
        setEscopo(scope);

        Node root = ast.getRoot();
        ast.Current(root);
        ast.setNode(new Node(packageNames.peek()).S("class", "package"));

        scopeFile.push(scope + "::" + ctx.ID().getText());
        astBaseSet(ctx);

        List<IvannosysGrammarParser.ImportsContext> imps = ctx.imports();
        if (imps.size() > 0) {
            Node imports = astSetCurrentNode("imports", ctx);
            imports.S("class", "imports");
            String alias, path, defaultname;
            String[] parts;

            for (IvannosysGrammarParser.ImportsContext imp : imps) {
                for (IvannosysGrammarParser.Import_partContext impPart : imp.import_part()) {
                    path = impPart.T_STRING().getText().replaceAll("\"", "");
                    parts = path.split("/");
                    defaultname = parts[parts.length - 1];

                    if (impPart.ID() != null) {
                        alias = impPart.ID().getText().replaceAll("\"", "");
                    } else {
                        alias = defaultname;
                    }
                    packages.put(alias, path);

                    imports.addFilho(new Node(alias)
                            .S("path", path)
                            .S("default", defaultname));
                }
            }
            astReturnLevel();
        }

        super.enterInit(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitInit(IvannosysGrammarParser.InitContext ctx) {

//        if (ctx.R_INIT_LIBRARY() != null) {
//            astReturnLevel();
//        }
        astReturnLevel();
        ast.Back();
        scopeStack.pop();
        scopeFile.pop();
        // Extracao de contantes, variaveis, funcoes e metodos
        if (packageNames.peek().equals("main")) {
//            ExtractMeta();

            Tipos.List();
//            Constantes.List();
            Variaveis.List();
            Functions.List();
            Interfaces.List();

        }
        packageNames.pop();
//        InitConstantes(ctx);
        super.exitInit(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    /**
     *
     *
     *
     */
    @Override
    public void enterNewstmt(IvannosysGrammarParser.NewstmtContext ctx) {
        astSetCurrentNode("new", ctx);
        astSetAtributo("class", "new");
        super.enterNewstmt(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitNewstmt(IvannosysGrammarParser.NewstmtContext ctx) {
        String size = "1";
        if (ctx.T_INTEIRO() != null) {
            size = ctx.T_INTEIRO().getText();
        }
        astAddChildren(size);
        astReturnLevel();
        super.exitNewstmt(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterFallthroughStmt(IvannosysGrammarParser.FallthroughStmtContext ctx) {
        astSetCurrentNode("fallthrough", ctx).S("class", "fallthrough.stmt");
        super.enterFallthroughStmt(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitFallthroughStmt(IvannosysGrammarParser.FallthroughStmtContext ctx) {
        astReturnLevel();
        super.exitFallthroughStmt(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterDelete(IvannosysGrammarParser.DeleteContext ctx) {
        astSetCurrentNode("delete", ctx);
        astSetAtributo("class", "delete");
        super.enterDelete(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitDelete(IvannosysGrammarParser.DeleteContext ctx) {
        astReturnLevel();
        super.exitDelete(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterDec_var_part(IvannosysGrammarParser.Dec_var_partContext ctx) {
        astSetCurrentNode("dec.var", ctx);
        astSetAtributo("class", "dec.var");
        super.enterDec_var_part(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitDec_var_part(IvannosysGrammarParser.Dec_var_partContext ctx) {
        try {
            DeclVar(ctx, astCurrent());
            astReturnLevel();
            super.exitDec_var_part(ctx); //To change body of generated methods, choose Tools | Templates.
        } catch (Exception ex) {
            Logger.getLogger(IvannosysListener.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    protected void DeclVar(ParserRuleContext ctx, Node node) throws Exception {
        int i = 0;
        String varname, t;
        Node variable,
                exprs = node.find("exprs"),
                type = node.find("type");

        ArrayList<String> types = new ArrayList<>();
        ArrayList<Node> ids = node.find("ids").childrens();
        ArrayList<ArrayList<Node>> indexes = new ArrayList<>();

        if (type != null) {
            // Quando declarado normal
            t = type.G("type");
            for (int k = 0; k < ids.size(); k++) {
                types.add(t);
                indexes.add(type.childrens());
            }
        } else {
            // Quando declarado encurtado
            //Todo fazer os tipos inferidos;
            for (Node e : exprs.childrens()) {
                switch (e.Class()) {
                    case "call":
//                        System.out.println("Call:" + e.getText());
                        try {
                            Node def = Functions.Get(e.getText());

                            for (Node rtype : def.find("dec.return").childrens()) {
                                types.add(rtype.G("type"));
                                indexes.add(new ArrayList<Node>());
                            }
                        } catch (Exception ex) {
                            errors.AddError(new Instruction()
                                    .S("class", "Call")
                                    .S("msg", ex.getMessage())
                                    .S("line", ctx.getStart().getLine())
                                    .S("col", ctx.getStart().getCharPositionInLine()));
                        }
                        break;
                    case "literal":
                        if (e.eq("subclass", "array")) {
                            ArrayList<Node> indc = new ArrayList<>();
                            indexes.add(indc);

                            indc.add(new Node("" + e.find("exprs").childrens().size()));
                            types.add(e.find("exprs").childrens().get(0).G("type"));
                        }
                        break;
                    default:
//                        System.out.println("E:" + e);
                        types.add(e.G("type"));
                        indexes.add(e.childrens());
                        break;
                }
            }
        }

        for (Node var : node.find("ids").childrens()) {
            varname = scopeStack.peek() + "." + var.getText();
            t = types.get(i);
            var.S("type", t)
                    .S("value", varname)
                    .S("class", "ID")
                    .S("array", "" + (indexes.get(i).size() > 0))
                    .S("array_size", "" + ArraySize(indexes.get(i)))
                    .copy("pointer", type);

            variable = new Node()
                    .S("global", "" + (scopeStack.peek().split("\\.").length == 1))
                    .S("name", var.getText())
                    .S("class", "selector")
                    .S("subclass", "operand");

            variable.copy("type,value,pointer,array,array_size", var);

            astBaseSet(ctx, variable);

            if (exprs != null) {
//                expr = exprs.childrens.G(i++);
//                variable.addFilho(expr);
            }
            variable.childrens = indexes.get(i);

//            System.out.println("DeclVAR:" + varname + "|" + variable);
            try {

                Variaveis.Add(varname, variable);
            } catch (Exception e) {
                errors.AddError(new Instruction()
                        .S("class", "Decl.Var")
                        .S("msg", e.getMessage())
                        .S("line", ctx.getStart().getLine())
                        .S("col", ctx.getStart().getCharPositionInLine()));
            }
            i++;
        }
    }

    protected String ArraySize(ArrayList<Node> indexes) throws Exception {
        int result = 1, v;
        for (Node index : indexes) {
            if (index.isNumber("value")) {
                v = index.getInt("value");
            } else {
                v = 1;
            }
            result *= v;
        }
        return "" + result;
    }

    @Override
    public void enterExpression_list(IvannosysGrammarParser.Expression_listContext ctx) {
        astSetCurrentNode("exprs", ctx);
        astSetAtributo("class", "exprs");
        super.enterExpression_list(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitExpression_list(IvannosysGrammarParser.Expression_listContext ctx) {
        astReturnLevel();
        super.exitExpression_list(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    //DECLARACAO DE CONSTANTES -------------------------------------------------
    @Override
    public void enterDec_const_part(IvannosysGrammarParser.Dec_const_partContext ctx) {
        astSetCurrentNode("const", ctx);
        astSetAtributo("class", "dec.const");
        astBaseSet(ctx);
        Node label = new Node(ctx.ID().getText());
        label.S("class", "ID");
        astAddChildren(label);
        super.enterDec_const_part(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitDec_const_part(IvannosysGrammarParser.Dec_const_partContext ctx) {
//        String id = ctx.ID().getText();
        astBaseSet(ctx);
        Node node = astCurrent()
                .S("constant", "true");
        ArrayList<Node> childrens = node.childrens();

        String id = childrens.get(0).getText();

        Node value = childrens.get(1);

        node.S("name", id)
                .S("type", value.G("type"))
                .S("value", value.getText());
        try {

            Variaveis.Add(scopeStack.peek() + "." + id, node);

        } catch (Exception e) {
            errors.AddError(
                    (Instruction) new Instruction()
                    .S("class", "Import")
                    .S("msg", e.getMessage())
                    .set("line", ctx.getStart().getLine())
                    .set("col", ctx.getStart().getCharPositionInLine()));
        }
        astReturnLevel();
        super.exitDec_const_part(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    public String getTypeOfPrimitive(IvannosysGrammarParser.Primitive_valueContext ctx) {
        if (ctx.T_BOOL_FALSE() != null || ctx.T_BOOL_TRUE() != null) {
            return Tipos.BOOLEAN;
        } else if (ctx.T_CHAR() != null) {
            return Tipos.CHAR;
        } else if (ctx.T_INTEIRO() != null) {
            return Tipos.INTEGER;
        }
        return "undefined";
    }

    @Override
    public void enterPrimitive_value(IvannosysGrammarParser.Primitive_valueContext ctx) {
        if (!this.ReadId.peek()) {
            return;
        }
        String classe = "", type = "", subclasse = "";

        if (ctx.T_BOOL_FALSE() != null || ctx.T_BOOL_TRUE() != null) {
            type = Tipos.BOOLEAN;
            classe = "value";
            subclasse = "boolean";

        } else if (ctx.T_CHAR() != null) {
            type = Tipos.CHAR;
            classe = "value";
            subclasse = "char";
        } else if (ctx.T_INTEIRO() != null) {
            type = Tipos.INTEGER;
            classe = "value";
            subclasse = "integer";
        } else {
            System.out.println("Error tipo desconhecido");
            return;
        }

        astSetCurrentNode(ctx.getText(), ctx);
        astSetAtributo("type", type);
        astSetAtributo("class", classe);
        astSetAtributo("subclass", subclasse);
        astBaseSet(ctx);
        super.enterPrimitive_value(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitPrimitive_value(IvannosysGrammarParser.Primitive_valueContext ctx) {
        if (!this.ReadId.peek()) {
            return;
        }
        astReturnLevel();
        super.exitPrimitive_value(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    // Definicao de tipos
    @Override
    public void enterType(IvannosysGrammarParser.TypeContext ctx) {
//        if (this.InsideType == 0) {

////            System.out.println("???? Type:" + typename + ":" + this.InsideType);
////            System.out.println("Type:" + ctx.getText());
//            this.TypePath = new LinkedList<>();
        astSetCurrentNode("type", ctx);
        astBaseSet(ctx);
        astSetAtributo("class", "type");

//        }
//
//        if (ctx.R_OP_AST() != null) {
//            astSetAtributo("pointer", "*");
//
//        } else if (ctx.ltype != "" && ctx.ltype != null && !ctx.ltype.equals("null")) {
//
//            String base = ctx.ltype;
//            Node imports = ast.getPackage(packageNames.peek()).find("imports");
//            if (imports != null) {
//                Node impt = imports.find(ctx.ltype);
//                if (impt != null) {
//                    base = impt.G("default");
//                }
//            }
////            System.out.println("Ctx ltype " + base);
//            this.TypePath.addFirst(base);
//        } else if (ctx.expression_seletor() != null) {
//
////            System.out.println("Ctx seletor " + ctx.expression_seletor().ID().getText());
//            this.TypePath.addFirst(ctx.expression_seletor().ID().getText());
//
//        } else if (ctx.type() != null) {
////            System.out.println("Ctx type " + ctx.type().getText());
//            this.TypePath.addFirst(ctx.type().getText());
//        } else if (ctx.ID() != null) {
////            System.out.println("Ctx id " + ctx.ID().getText());
//            this.TypePath.addFirst(ctx.ID().getText());
//        }
//
//        this.InsideType++;
        super.enterType(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitType(IvannosysGrammarParser.TypeContext ctx) {
        String typename = ctx.ltype;
        // Adiciona o pacote local se não for um tipo primitivo e não possui um pacote

        if (!Tipos.Primitive(typename)) {
            // local type
            if (typename.indexOf(".") < 0) {
                typename = packageNames.peek() + "." + typename;

            } else {
                // imported type
                // Carrega pacote se não for o pacote local
                String[] parts = typename.split("\\.");
                if (!parts[0].equals(packageNames.peek())) {
                    try {
                        Imports.Load(parts[0]);
                    } catch (Exception ex) {
                        Logger.getLogger(IvannosysListener.class.getName()).log(Level.SEVERE, null, ex);
                        return;
                    }

                    Node imports = ast.getPackage(packageNames.peek()).find("imports");
                    if (imports != null) {
                        Node impt = imports.find(ctx.ltype);
                        if (impt != null) {
                            typename = impt.G("default") + "." + ctx.ltype;
                        }
                    }
                }
            }
        }

//        System.out.println("Out of type :" + ctx.ltype + ":" + ctx.getText());
//        System.out.println("TYPE:" + typename);
        Node type = astCurrent().S("type", typename);

        ArrayList<Node> indexes = new ArrayList<>();

        for (Node x : type.childrens()) {
            if (x.eq("class", "index")) {
                indexes.add(x);
            }
        }
        type.childrens = indexes;
        astReturnLevel();
//        }

        super.exitType(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterIndexedType(IvannosysGrammarParser.IndexedTypeContext ctx) {
        if (ctx.index() != null) {
            String val = ctx.index().expression().getText();
            if (!Utils.isNumber(val)) {
                Node constante = Variaveis.Get(scopeStack.peek() + "." + val);
                if (constante != null) {
                    val = constante.G("value");
                }
            }

            astAddChildren(val)
                    .S("class", "index");
        }
        super.enterIndexedType(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterTypename(IvannosysGrammarParser.TypenameContext ctx) {
        if (ctx.R_OP_AST() != null) {
            astSetAtributo("pointer", "*");
//            System.out.println("ENTERTYPENAME = " + ctx.ltype);
        }
        super.enterTypename(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitTypename(IvannosysGrammarParser.TypenameContext ctx) {
        super.exitTypename(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterDef_type(IvannosysGrammarParser.Def_typeContext ctx) {
        astSetCurrentNode(ctx.ID().getText(), ctx);
        astSetAtributo("class", "dec.type");
        astBaseSet(ctx);

        super.enterDef_type(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitDef_type(IvannosysGrammarParser.Def_typeContext ctx) {

        Node defType = astCurrent();
        try {

            Tipos.Add(packageNames.peek() + "." + defType.getText(), defType);

        } catch (Exception e) {
            errors.AddError((Instruction) new Instruction()
                    .S("class", "Import")
                    .S("msg", e.getMessage())
                    .S("line", ctx.getStart().getLine())
                    .S("col", ctx.getStart().getCharPositionInLine()));
        }
        astReturnLevel();
        super.exitDef_type(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterArguments(IvannosysGrammarParser.ArgumentsContext ctx) {
        // Chamda de funcao
        astSetCurrentNode("arguments", ctx);
        if (ctx.expression_list() != null) {
            // Declaracao
        } else if (ctx.expression_list_typed().size() > 0) {
        }
//            astSetCurrentNode("args", ctx);
        super.enterArguments(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitArguments(IvannosysGrammarParser.ArgumentsContext ctx) {
        astReturnLevel();
        super.exitArguments(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterExpression_list_typed(IvannosysGrammarParser.Expression_list_typedContext ctx) {
        astSetCurrentNode("argument", ctx).S("class", "argument");
        super.enterExpression_list_typed(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitExpression_list_typed(IvannosysGrammarParser.Expression_list_typedContext ctx) {
        Node argument = astCurrent();
        if (argument != null && argument.find("ids") != null) {
            try {
                //            System.out.println("Argument:" + argument);
                DeclVar(ctx, argument);
            } catch (Exception ex) {
                Logger.getLogger(IvannosysListener.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        astReturnLevel();
        super.exitExpression_list_typed(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterId_list(IvannosysGrammarParser.Id_listContext ctx) {
        astSetCurrentNode("ids", ctx);

        for (TerminalNode id : ctx.ID()) {
            astAddChildren(id.getText());
        }

        super.enterId_list(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitId_list(IvannosysGrammarParser.Id_listContext ctx) {
        astReturnLevel();
        super.exitId_list(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterStructType(IvannosysGrammarParser.StructTypeContext ctx) {
        super.enterStructType(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitStructType(IvannosysGrammarParser.StructTypeContext ctx) {
        Node decl = astCurrent(), type;
        ArrayList<Node> attribs = new ArrayList<>();
        ArrayList<Node> decls = decl.childrens();
        System.out.println("StructType:" + decl);
        for (Node ids : decl.findAll("ids", "value")) {
            type = decls.get(decls.indexOf(ids) + 1);
            for (Node id : ids.childrens()) {
                astBaseSet(ctx, id);
                id.Set("class", "attr");
                id.addFilho(type);
                attribs.add(id);
            }
        }
        decl.childrens = attribs;
        super.exitStructType(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterComposite(IvannosysGrammarParser.CompositeContext ctx) {

//        astSetCurrentNode("composite", ctx);
        super.enterComposite(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitComposite(IvannosysGrammarParser.CompositeContext ctx) {
//        astReturnLevel();

        super.exitComposite(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterArrayType(IvannosysGrammarParser.ArrayTypeContext ctx) {
        astCurrent()
                .S("class", "literal")
                .S("value", "literal")
                .S("subclass", "array");
        super.enterArrayType(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitArrayType(IvannosysGrammarParser.ArrayTypeContext ctx) {
        super.exitArrayType(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterFieldDecl(IvannosysGrammarParser.FieldDeclContext ctx) {

        super.enterFieldDecl(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitFieldDecl(IvannosysGrammarParser.FieldDeclContext ctx) {
//        if (ctx.id_list() != null) {
//            for (TerminalNode x : ctx.id_list().ID()) {
////                astSetCurrentNode(x.getText(), ctx);
////                astSetAtributo("class", "attr");
////                astReturnLevel();
//            }
//        } else if (ctx.anon_field() != null) {
////            ctx.anon_field().typename().getText()
//        }
//        Node decl = astCurrent(), type;
//        ArrayList<Node> attribs = new ArrayList<>();
//        ArrayList<Node> decls = decl.childrens();
//
//        for (Node ids : decl.findAll("ids", "value")) {
//            type = decls.get(decls.indexOf(ids) + 1);
//            for (Node id : ids.childrens()) {
//                System.out.println("Add attr:" + id + type);
//                astBaseSet(ctx, id);
//                id.Set("class", "attr");
//                id.addFilho(type);
//                attribs.add(id);
//            }
//        }
//        decl.childrens = attribs;

        super.exitFieldDecl(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterIndex(IvannosysGrammarParser.IndexContext ctx) {
        super.enterIndex(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitIndex(IvannosysGrammarParser.IndexContext ctx) {
        super.exitIndex(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    // Definicao de um bloco de instrucoes
    @Override
    public void enterDef_block(IvannosysGrammarParser.Def_blockContext ctx) {
        astSetCurrentNode("stmts", ctx);
        astSetAtributo("class", "stmts");
        astBaseSet(ctx);
        super.enterDef_block(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitDef_block(IvannosysGrammarParser.Def_blockContext ctx) {
        astReturnLevel();
        super.exitDef_block(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    // Definicao do retorno de uma funcao
    @Override
    public void enterReturn_stmt(IvannosysGrammarParser.Return_stmtContext ctx) {
        astSetCurrentNode("return", ctx);
        astSetAtributo("class", "return");
        astBaseSet(ctx);
        super.enterReturn_stmt(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitReturn_stmt(IvannosysGrammarParser.Return_stmtContext ctx) {
        astReturnLevel();
        super.exitReturn_stmt(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterInc_dec(IvannosysGrammarParser.Inc_decContext ctx) {
        astSetCurrentNode("incdec.stmt", ctx);
        astSetAtributo("class", "incdec");
        astSetCurrentNode(ctx.op.getText(), ctx);
        astSetAtributo("class", "operator");
        astReturnLevel();
        super.enterInc_dec(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitInc_dec(IvannosysGrammarParser.Inc_decContext ctx) {
        astReturnLevel();
        super.exitInc_dec(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    //DECLARACAO DE FUNCOES
    protected String __functionName__(IvannosysGrammarParser.Def_functionContext ctx) {
        return ((ctx.name != null)
                ? ctx.name.getText() : ("anonymous." + this.uniq++));
    }

    @Override
    public void enterDef_function(IvannosysGrammarParser.Def_functionContext ctx) {
        String id = this.__functionName__(ctx), classe;
//        setEscopo("func." + id);
        setEscopo(id);

        astSetCurrentNode(id, ctx);
        astBaseSet(ctx);
        if (ctx.receive_type() != null) {
            astSetAtributo("method", "true");
            classe = "dec.method";
        } else {
            classe = "dec.func";
        }

        astSetAtributo("class", classe);
        super.enterDef_function(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitDef_function(IvannosysGrammarParser.Def_functionContext ctx) {

        Node node = astCurrent();
        ArrayList<String> name = null;
        if (ctx.receive_type() != null) {
            astSetAtributo("method", "true");
            name = new ArrayList<String>();
            name.add(packageNames.peek());
            name.add("method");
            name.add("(" + node.find("receive.type").find("type").G("type") + ")"); // type
        } else {
            if (name == null) {
                name = new ArrayList<String>();
                name.add(packageNames.peek());
            }
        }
        // Adiciona o nome da funcao
        name.add(node.getText());
        node.S("name", node.getText());

        try {
            astBaseSet(ctx, node);
            Functions.Add(Utils.Join(name, "."), node);

        } catch (Exception e) {
            errors.AddError(
                    (Instruction) new Instruction()
                    .S("class", "Decl.Func")
                    .S("msg", e.getMessage())
                    .set("line", ctx.getStart().getLine())
                    .set("col", ctx.getStart().getCharPositionInLine()));
        }

        scopeStack.pop();
        astReturnLevel();
        super.exitDef_function(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterReceive_type(IvannosysGrammarParser.Receive_typeContext ctx) {
        astSetCurrentNode("receive.type", ctx);
        astAddChildren(ctx.ID().getText()).S("class", "ID");

        super.enterReceive_type(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitReceive_type(IvannosysGrammarParser.Receive_typeContext ctx) {
        ArrayList<Node> parts = astCurrent().childrens();
        String varname = parts.get(0).getText();
        String fullname = scopeStack.peek() + "." + varname;
//        astBaseSet(ctx);
        Node var = new Node(fullname);
        parts.get(0).S("value", fullname);
        var.S("name", varname)
                .S("pointer", parts.get(1).G("pointer"))
                .S("type", parts.get(1).G("type"));

//        System.out.println("POINTER[" + fullname + "]:" + parts.get(1).G("pointer"));
        try {

            Variaveis.Add(fullname, var);
        } catch (Exception e) {
            errors.AddError(
                    (Instruction) new Instruction()
                    .S("class", "Import")
                    .S("msg", e.getMessage())
                    .set("line", ctx.getStart().getLine())
                    .set("col", ctx.getStart().getCharPositionInLine()));
        }
        astReturnLevel();
        super.exitReceive_type(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterReturn_dec(IvannosysGrammarParser.Return_decContext ctx) {
        astSetCurrentNode("dec.return", ctx);
        super.enterReturn_dec(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitReturn_dec(IvannosysGrammarParser.Return_decContext ctx) {
        astReturnLevel();
        super.exitReturn_dec(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterDef_interface(IvannosysGrammarParser.Def_interfaceContext ctx) {
        astSetCurrentNode(ctx.ID().getText(), ctx);
        astSetAtributo("class", "dec.interface");
        astSetAtributo("package", "");

        super.enterDef_interface(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitDef_interface(IvannosysGrammarParser.Def_interfaceContext ctx) {
        Node node = astCurrent();
        Interfaces.Add(packageNames.peek() + "." + node.getText(), node);
        astReturnLevel();
        super.exitDef_interface(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterFunc_spec(IvannosysGrammarParser.Func_specContext ctx) {
        astSetCurrentNode(ctx.ID().getText(), ctx);
        astSetAtributo("class", "desc.method");
        super.enterFunc_spec(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitFunc_spec(IvannosysGrammarParser.Func_specContext ctx) {
        astReturnLevel();
        super.exitFunc_spec(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterDec_var_short(IvannosysGrammarParser.Dec_var_shortContext ctx) {
        astSetCurrentNode("dec.var.short", ctx);
        astSetAtributo("class", "def.assign");
//        List<TerminalNode> ids = ctx.id_list().ID();
//        List<IvannosysGrammarParser.ExpressionContext> expr = ctx.expression_list().expression();
//        int idsLen = ids.size(), exprLen = expr.size();
//
//        if (idsLen == exprLen) {// Caso OK
////            Node inode;
////            for (TerminalNode id : ids) {
////                inode = astAddChildren(id.getText());
////                inode.S("class", "ID");
////            }
//
//        } else if (idsLen < exprLen) {// Menos endereco de atribuicao
//
//        } else {// Mais endereco de atribuicao
//
//        }

        super.enterDec_var_short(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitDec_var_short(IvannosysGrammarParser.Dec_var_shortContext ctx) {
        try {
            DeclVar(ctx, astCurrent());
            astReturnLevel();
            super.exitDec_var_short(ctx); //To change body of generated methods, choose Tools | Templates.
        } catch (Exception ex) {
            Logger.getLogger(IvannosysListener.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void enterDef_for(IvannosysGrammarParser.Def_forContext ctx) {
        String id = "for_" + this.__uniq__();
        setEscopo(id);
        astSetCurrentNode(id, ctx);
        astSetAtributo("class", "for.stmt");
        astBaseSet(ctx);
        super.enterDef_for(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitDef_for(IvannosysGrammarParser.Def_forContext ctx) {
        scopeStack.pop();
        astReturnLevel();
        super.exitDef_for(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterIncrement(IvannosysGrammarParser.IncrementContext ctx) {
        astSetCurrentNode("increment", ctx);
        super.enterIncrement(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitIncrement(IvannosysGrammarParser.IncrementContext ctx) {
        astReturnLevel();
        super.exitIncrement(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterInitialization(IvannosysGrammarParser.InitializationContext ctx) {
        astSetCurrentNode("initialization", ctx);
        super.enterInitialization(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitInitialization(IvannosysGrammarParser.InitializationContext ctx) {
        astReturnLevel();
        super.exitInitialization(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterTest(IvannosysGrammarParser.TestContext ctx) {
        astSetCurrentNode("test", ctx).S("class", "test");
        super.enterTest(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitTest(IvannosysGrammarParser.TestContext ctx) {
        astReturnLevel();
        super.exitTest(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterFor_clause(IvannosysGrammarParser.For_clauseContext ctx) {
//        astSetCurrentNode("ctrl", ctx);
//        astSetAtributo("class", "ctrl");
//        astSetAtributo("subclass", "clause");
        super.enterFor_clause(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitFor_clause(IvannosysGrammarParser.For_clauseContext ctx) {
//        astReturnLevel();
        super.exitFor_clause(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterFor_each(IvannosysGrammarParser.For_eachContext ctx) {
        astSetCurrentNode("range", ctx);
        astSetAtributo("class", "range");

//        this.ReadId.push(false);
//        astSetAtributo("subclass", "each");
        super.enterFor_each(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitFor_each(IvannosysGrammarParser.For_eachContext ctx) {
//        this.ReadId.pop();
        Node range = astCurrent(),
                ids = new Node("ids");
        range.S("type", ctx.R_SHORT_VAR() != null ? "dec" : "assign");

        ids.S("class", "ids");

        for (Node n : range.findAll("selector", "class")) {
            ids.addFilho(n);
            range.removeFilho(n);
        }

        astAddChildren(ids);
        astReturnLevel();

        super.exitFor_each(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterUnary_expr(IvannosysGrammarParser.Unary_exprContext ctx) {
//        System.out.println("Unary:" + ctx.getText());
        if (ctx.op != null) {
            String subclass, op = ctx.op.getText();

            switch (op) {
                case "&":
                    subclass = "address";
                    break;
                case "!":
                    subclass = "negation.bool";
                    break;
                case "+":
                    subclass = "add";
                    break;
                case "-":
                    subclass = "negation.arith";
                    break;
                case "*":
                    subclass = "content";
                    break;
                default:
                    return;
            }

            astSetCurrentNode("unary", ctx)
                    .S("class", "unary")
                    .S("subclass", subclass);

            astAddChildren(op)
                    .S("class", "operator");
        }

        super.enterUnary_expr(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitUnary_expr(IvannosysGrammarParser.Unary_exprContext ctx) {
        if (ctx.op != null) {
            Node c = astCurrent();
            c.S("type", c.childrens().get(1).G("type"));
            astReturnLevel();
        }
        super.exitUnary_expr(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterDef_assign_op(IvannosysGrammarParser.Def_assign_opContext ctx) {
        astSetCurrentNode("def.assign", ctx);
        astSetAtributo("class", "def.assign");
        IvannosysGrammarParser.Assign_modifyContext mod = ctx.assign_modify();
        if (mod != null) {
            astSetAtributo("modify", mod.getText());
        }

        astBaseSet(ctx);
//        super.enterDef_assign_op(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitDef_assign_op(IvannosysGrammarParser.Def_assign_opContext ctx) {
        for (Node address : astCurrent().first().childrens()) {
            address.S("access", "write");
        }

        astReturnLevel();
//        super.exitDef_assign_op(ctx); //To change body of generated methods, choose Tools | Templates.
    }

//    //CONTROLE
//    //IF-ELSE
    @Override
    public void enterDef_if(IvannosysGrammarParser.Def_ifContext ctx
    ) {
        astSetCurrentNode("if." + this.__uniq__(), ctx);
        astSetAtributo("class", "if.stmt");
        astBaseSet(ctx);
        super.enterDef_if(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitDef_if(IvannosysGrammarParser.Def_ifContext ctx) {

        astReturnLevel();
        super.exitDef_if(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    //IFBLOCK
    @Override
    public void enterDef_if_block(IvannosysGrammarParser.Def_if_blockContext ctx) {
        astSetCurrentNode("if.case.stmt", ctx);
        astSetAtributo("class", "if.case.stmt");
        astBaseSet(ctx);
        super.enterDef_if_block(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitDef_if_block(IvannosysGrammarParser.Def_if_blockContext ctx) {
        astReturnLevel();
        super.exitDef_if_block(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterRange(IvannosysGrammarParser.RangeContext ctx) {
        astSetCurrentNode("range.gen", ctx);
        super.enterRange(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitRange(IvannosysGrammarParser.RangeContext ctx) {
        astReturnLevel();
        super.exitRange(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterPrimary_expr(IvannosysGrammarParser.Primary_exprContext ctx) {
        String base = "",
                funcname = "",
                subclasse = "",
                classe = "selector",
                type = "",
                pointer = "",
                name = "",
                classType = "",
                ctxVar = "";

        Node d = new Node("");
        astBaseSet(ctx, d);

        if (ctx.getParent().getClass().getName().equals("grammar.IvannosysGrammarParser$Primary_exprContext")) {
//            System.out.println("Return Primary_expr:" + ctx.getText());
            return;
        } else if (ctx.arguments() != null) {
            base = ctx.primary_expr().getText();
            classe = "call";
            subclasse = "arguments";
            // É o acesso de uma funcao do pacote atual
            if (base.indexOf(".") == -1) {
                funcname = base;
                base = packageNames.peek() + "." + base;
                name = base;
            } else {
                String[] parts = base.split("\\.");
                if (parts.length >= 2 && !packages.containsKey(parts[0])) {
//                    System.out.println("Base:" + +"." + base);
                    // É sempre um metodo
                    ArrayList<String> p = new ArrayList<>();
                    p.add(scopeStack.peek());
                    for (int k = 0; k < parts.length - 1; k++) {
                        p.add(parts[k]);
                    }
                    ctxVar = Utils.Join(p, ".");
                    String t = Variaveis.Type(ctxVar);

                    funcname = parts[parts.length - 1];
                    name = funcname;
                    base = packageNames.peek() + ".method.(" + t + ")." + funcname;

                } else {
                    name = funcname = parts[1];
                    // É um acesso de uma funcao de um pacote
                }
            }

        } else if (ctx.operand() != null) {
            base = ctx.operand().getText();

            if (ctx.operand().primitive_value() != null) {
                classType = "value";
                type = getTypeOfPrimitive(ctx.operand().primitive_value());
            } else {
                try {
                    base = scopeStack.peek() + "." + base;
                    type = Variaveis.TypeOf(base);

                    pointer = Variaveis.Get(base).G("pointer");
                } catch (Exception ex) {
//                    Logger.getLogger(IvannosysListener.class.getName()).Log(Level.SEVERE, null, ex);
                }
            }

            subclasse = "operand";
        } else if (ctx.expression_seletor() != null) {
            try {
                base = scopeStack.peek() + "." + ctx.primary_expr().getText() + "." + ctx.expression_seletor().ID().getText();
                subclasse = "selector";
                type = Variaveis.TypeOf(base);
            } catch (Exception ex) {
//                Logger.getLogger(IvannosysListener.class.getName()).Log(Level.SEVERE, null, ex);
            }

        } else if (ctx.index() != null) {
            try {
                subclasse = "index";
                base = scopeStack.peek() + "." + ctx.id;
                type = Variaveis.TypeOf(base);
            } catch (Exception ex) {
//                Logger.getLogger(IvannosysListener.class.getName()).Log(Level.SEVERE, null, ex);
            }
        }

        ast.setNode(d.S("value", base)
                .S("class", classe)
                .S("subclass", subclasse)
                .S("type", type)
                .S("name", name)
                .S("pointer", pointer)
                .S("classType", classType));

        if (funcname != "") {

            d.S("ctx", ctxVar).S("funcname", funcname);
        }

        this.ReadId.push(false);
//        System.out.println("PrimaryExpr:" + base + "<>" + ctx.getText());
        super.enterPrimary_expr(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitPrimary_expr(IvannosysGrammarParser.Primary_exprContext ctx) {
        if (ctx.getParent().getClass().getName().equals("grammar.IvannosysGrammarParser$Primary_exprContext")) {
            return;
        } else if (ctx.arguments() != null) {
//            System.out.println("packageName:" + packageName);

//            Functions.add(, null);
//            base = ctx.primary_expr().getText();
//            classe = "call";
//            subclasse = "arguments";
        }

        this.ReadId.pop();
        astReturnLevel();
        super.exitPrimary_expr(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterExpression_seletor(IvannosysGrammarParser.Expression_seletorContext ctx) {
        super.enterExpression_seletor(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitExpression_seletor(IvannosysGrammarParser.Expression_seletorContext ctx) {
        super.exitExpression_seletor(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterExpression(IvannosysGrammarParser.ExpressionContext ctx) {
        if (ctx.op != null) {  // expr_operation
            String op = ctx.op.getText(), classe = "", subclasse = "", type = "";

            switch (op) {
                case "||":
                case "&&":
                case "==":
                case "!=":
                case "<":
                case "<=":
                case ">=":
                case ">":
                    classe = "expr";
                    subclasse = "bool";
                    type = "bool";
                    //Booleana
                    break;
                case "+":
                case "-":
                case "*":
                case "/":
                case "%":
                case "&":
                case "^":
                case "|":
                case "<<":
                case ">>":
                    classe = "expr";
                    subclasse = "arith";
                    type = "int";
                //Aritimeticas

            }

            astSetCurrentNode(op, ctx)
                    .S("type", type)
                    .S("class", classe)
                    .S("subclass", subclasse);

        } else { // expr_unary

        }

        super.enterExpression(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitExpression(IvannosysGrammarParser.ExpressionContext ctx) {
        if (ctx.op != null) {
            astReturnLevel();
        }
        super.exitExpression(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterOperand(IvannosysGrammarParser.OperandContext ctx) {
        if (this.ReadId.peek() && ctx.Value != "") {
            astSetCurrentNode(ctx.Value, ctx);
        }

        super.enterOperand(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitOperand(IvannosysGrammarParser.OperandContext ctx) {

        if (this.ReadId.peek() && ctx.Value != "") {
            String type;
            Node operand = astCurrent();
            if (ctx.primitive_value() != null) {
                type = getTypeOfPrimitive(ctx.primitive_value());
            } else {
                Node var = Variaveis.Get(ctx.ID().getText());
                type = var.G("type");
                operand.copy("pointer", var);
            }
            operand.S("class", "operand").S("type", type);

            astReturnLevel();
        }

        super.exitOperand(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterLabel_stmt(IvannosysGrammarParser.Label_stmtContext ctx) {
        astSetCurrentNode(ctx.ID().getText(), ctx).S("class", "label.stmt");
        super.enterLabel_stmt(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitLabel_stmt(IvannosysGrammarParser.Label_stmtContext ctx) {
        astReturnLevel();
        super.exitLabel_stmt(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterDef_switch(IvannosysGrammarParser.Def_switchContext ctx) {
        this.insideSwitch = true;
        astSetCurrentNode("switch." + this.__uniq__(), ctx);
        astSetAtributo("class", "switch.stmt");
        astBaseSet(ctx);
        super.enterDef_switch(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterFlux_control(IvannosysGrammarParser.Flux_controlContext ctx) {
        Node ctrlStmt = astSetCurrentNode(ctx.control, ctx)
                .S("class", "ctrl.stmt");
        if (ctx.ID() != null) {
            ctrlStmt.S("label", ctx.ID().getText());
        }
        super.enterFlux_control(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitFlux_control(IvannosysGrammarParser.Flux_controlContext ctx) {
        astReturnLevel();
        super.exitFlux_control(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitDef_switch(IvannosysGrammarParser.Def_switchContext ctx) {
        astReturnLevel();
        this.insideSwitch = false;
        super.exitDef_switch(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterDef_case(IvannosysGrammarParser.Def_caseContext ctx) {
        astSetCurrentNode("switch.case", ctx);
        astSetAtributo("class", "def.case");
        astBaseSet(ctx);
        super.enterDef_case(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitDef_case(IvannosysGrammarParser.Def_caseContext ctx) {
        // retorno do switch
//        Node c =astCurrent();
        astReturnLevel();
        super.exitDef_case(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void enterStatement_list(IvannosysGrammarParser.Statement_listContext ctx) {
        astSetCurrentNode("stmts", ctx);
        astSetAtributo("class", "stmts");
        super.enterStatement_list(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void exitStatement_list(IvannosysGrammarParser.Statement_listContext ctx) {
        astReturnLevel();
        super.exitStatement_list(ctx); //To change body of generated methods, choose Tools | Templates.
    }

    /*AST FUNCTIONS ----------------------------------------------------------*/
    protected void astBaseSet(ParserRuleContext ctx) {
        astBaseSet(ctx, astCurrent());
    }

    protected void astBaseSet(ParserRuleContext ctx, Node n) {
        n.S("file", scopeFile.peek())
                .S("scope", scopeStack.peek())
                .S("line", "" + ctx.getStart().getLine())
                .S("col", "" + ctx.getStart().getCharPositionInLine());
    }

    protected String getNodeType(RuleContext node) {
        return node.getClass().getSimpleName().replace("Context", "");
    }

    protected void setEscopo(String escopo) {
        String ant = scopeStack.empty() ? "" : scopeStack.peek() + ".@";
        scopeStack.push(ant + escopo);
    }

    protected Node astAddChildren(String n) {
        return astAddChildren(new Node(n));
    }

    protected Node astAddChildren(Node n) {
        this.ast.addChildren(n);
        return n;
    }

    protected Node astSetCurrentNode(String n, ParserRuleContext ctx) {
        Node x = new Node(n);
        astBaseSet(ctx, x);
        return this.ast.setNode(x);
    }

    protected Node astReturnLevel() {
        return this.ast.setParentToCurrent();
    }

    protected void astSetAtributo(String atrib, String valor) {
        this.ast.setAtributo(atrib, valor);
    }

    AbstractSyntaxTree getAbstractSyntaxTree() {
        return this.ast;
    }

    protected void astConcatAtributo(String atrib, String valor) {
        String at = this.ast.getAtributo(atrib);
        this.ast.setAtributo(atrib, at + "," + valor);
    }

    protected String astGetAtributo(String atrib) {
        return this.ast.getAtributo(atrib);
    }

    protected Node astCurrent() {
        return this.ast.getCurrent();
    }

    protected void astSetAtributo(Node parent, String atrib, String valor) {
        parent.S(atrib, valor);
    }

    protected int __uniq__() {
        return this.uniq++;
    }

//    protected String getTypeOfVar(String base) {
//        System.out.println("getTypeOfVar:" + base);
//        Node var = Variaveis.Get(base);
//        if (var != null) {
//            return var.G("type");
//        } else {
//            return "undefined";
//        }
//    }
}
