/* * 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 API; import ast.Node; import common.Instruction; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * * @author Eugenio */ public class Variables { public static Integer indexCount = 0; public static HashMap vars; public static HashMap scopes; public static String UNDEFINED = "undefined"; public static String currentKey; public static Pattern BASEVEXPR = Pattern.compile("(\\w+(\\.@\\w+)*\\.\\w+)"); public static String CLEARBASEVAR = "(\\w+)(\\.@\\w+)*(\\.)"; public static String SCOPE_LEVE = "(\\.@\\w+)((\\.\\w)*)"; public static String VARNAME = "(\\.\\w*)+"; public static void _init() { vars = new HashMap<>(); scopes = new HashMap<>(); } public static void Add(String id, Node var) throws Exception { // System.out.println("AddVar:" + id + "\n" + var); if (vars.containsKey(id)) { String[] parts = id.split("\\."); throw new Exception("'" + parts[parts.length - 1] + "' previamente declarado em na linha " + vars.get(id).Get("line", "")); // throw new Exception("'" + id + "' previamente declarado em na linha " + vars.Get(id).Get("line", "")); } var.Set("public", Base.IsPublic(var.Get("name")) ? "true" : "false"); // System.out.println("Add var:" + var.Get("name")); vars.put(id, var); } public static boolean Defined(String id) { return Defined(id, true); } public static boolean Defined(String id, boolean clear) { if (clear) { id = BaseVar(id); } // System.out.println("Defined:"+id+":"+vars.containsKey(id)); return vars.containsKey(id); } public static String BaseVar(String id) { Matcher match = BASEVEXPR.matcher(id); while (match.find()) { return match.group(1); } return id; } public static String TypeOf(String varname) throws Exception { // System.out.println("Type of " + varname); Node var = Get(varname); Node tmp, t; String type = "undefined"; // System.out.println("Type:" + varname + " var: " + var); if (var != null) { // System.out.println("TypeOf:\n" + varname + "\n" + var + "\n" + var.contem("scope", ".")); String path; if (var.contem("scope", ".")) { path = varname.replace(var.Get("fullname"), ""); } else { ArrayList parts = new ArrayList<>(); for (String s : var.Get("fullname").split("\\.")) { parts.add(s); } parts.add(1, "(\\.@\\w+)+\\."); // System.out.println("PARTS:" + Utils.Join(parts, "")); path = varname.replaceFirst(Utils.Join(parts, ""), ""); } // System.out.println("path:" + var.Get("fullname") + "---" + path); // Sem path if (path.length() > 0) { ArrayList parts = new ArrayList<>(Arrays.asList(path.split("\\."))); parts.remove(0); // Remove a primaira parte que é uma string vazia String typed = var.Get("type"), attr; t = Types.Get(typed); while (parts.size() > 0) { if (Types.Primitive(typed)) { return typed; } if (t == null) { throw new Exception(String.format("Tipo '%s' não definido", typed)); } attr = parts.remove(0); tmp = t.find(attr); if (tmp == null) { throw new Exception(String.format("Tipo '%s' não possui o atributo '%s'", typed, attr)); } typed = tmp.find("type").Get("type"); t = Types.Get(typed); } // System.out.println("Type:" + t + type); type = t.Get("type"); } else { type = var.Get("type"); } } // System.out.println("Type of:" + varname + ":" + type); return type; } public static Node Get(String id) { // System.out.println("Get VAR:" + id); String x = id; id = BaseVar(id); // System.out.println("Get:" + id + "=" + x); if (Defined(id, false)) { // System.out.println("##################### Var defined:" + id); return vars.get(id); } List items = Arrays.asList(id.split("\\.")); // Minima representacao de uma variavel sendo o pacote e o id if (items.size() <= 2) { return null; } List parts = items.subList(0, items.size() - 2); parts = new ArrayList<>(parts); parts.add(items.get(items.size() - 1)); // System.out.println("Get ID:" + Utils.Join(parts, ".")); return Get(Utils.Join(parts, ".")); } /** * Metodos antigos */ /** * Adiciona uma variavel em um eScopo * * @param name * @param type * @param scope * @param array */ public static void add(String name, String type, String scope, Node n) { String key = name + ":" + scope; vars.put(key, n); if (!scopes.containsKey(scope)) { scopes.put(scope, new Instruction()); } scopes.get(scope).Set(name, type); } public static String type(String id, String scope) { if (exist(id, scope)) { return vars.get(currentKey).Get("type"); } return UNDEFINED; } /** * Retorna true Se uma variavel é aceSSivel de um determinado eScopo. * * @param name * @param scope * @return */ public static boolean accessible(String name, String scope) { return type(name, scope) != UNDEFINED; } /** * Verifica Se uma variavel foi declarada em um determinado eScopo * * @param name * @param scope * @return */ public static boolean exist(String name, String scope) { String key = name + ":" + scope; if (vars.containsKey(key)) { currentKey = key; return true; } String[] path = scope.split(",", 2); if (path.length == 2) { return exist(name, path[1]); } key = name + ":" + path[0]; if (vars.containsKey(key)) { currentKey = key; return true; } return false; } /** * Verifica Se uma variavel foi declarada por meio do no da AST * * @param nome * @param escopo * @return */ public static boolean exist(Node var) { return exist(var.getText(), var.Get("scope")); } public static Node get(Node n) { return exist(n) ? vars.get(currentKey) : null; } public static Node get(String name, String scope) { return exist(name, scope) ? vars.get(currentKey) : null; } public static String printScope(String scope) { if (!scopes.containsKey(scope)) { return "Scope " + scope + " não definido!"; } return "Scope{" + scope + "}\n" + scopes.get(scope); } /** * * DAQUI PRA CIMA O RESTO APAGA * * */ /** * Verifica Se uma dada variavel é um array * * @param varname * @return */ public static boolean isArray(String varname) { return (varname.lastIndexOf("[") >= 0); } public static String clearName(String nome) { return nome.split("\\[")[0].replace("&", ""); } // /** // * Retorna uma variavel em um dado escopo do programa // * // * @param nome nome da variavel // * @param escopo escopo da variavel (onde foi declarada) // * @return Node | null // * @throws Exception // */ // public static Node var(String nome, String escopo) { // existe(nome, escopo); // return varsNodes.Get(index.Get(baseName(nome) + ":" + escopo)); // // } // // /** // * Adiciona uma variavel em um dado escopo do programa // * // * @param nome nome da variavel // * @param escopo escopo da variavel (onde foi declarada) // * @param var no com todos os dados da variavel // * @throws Exception // */ // public static void var(String nome, String escopo, Node var) { // existe(nome, escopo); // varsNodes.put(index.Get(baseName(nome) + ":" + escopo), var); // } // // public static String tipo(Node variavel) { // return tipo(variavel.Get("value"), variavel.Get("escopo")); // } // public static String tipo(String nome, String escopo) { // nome = baseName(nome); // try { // existe(nome, escopo); // return types.Get(index.Get(nome + ":" + escopo)); // } catch (Exception e) { // return _tipo(nome, escopo); // } // } // protected static String _tipo(String nome, String escopo) { // nome = baseName(nome); // try { // String[] escopos = escopo.split(",", 2); // if (escopos.length == 2) { // return tipo(nome, escopos[1]); // } // existe(nome, escopos[0]); // return types.Get(index.Get(nome + ":" + escopos[0])); // } catch (Exception e) { // return null; // } // } // /** // * Retorna uma variavel do escopo, caso não a encontre vai buscar no escopo // * pai. Se chegar ao no root e não encontrar a variavel, será retornado o // * valor null. // * // * @param nome // * @param escopo // * @return // */ // public static Node find(Node variavel) { // if (variavel == null) { // return null; // } // return find(variavel.getText(), variavel.Get("escopo")); // } // // /** // * Retorna uma variavel do escopo, caso não a encontre vai buscar no escopo // * pai. Se chegar ao no root e não encontrar a variavel, será retornado o // * valor null. // * // * @param nome // * @param escopo // * @return // */ // public static Node find(String nome, String escopo) { // nome = baseName(nome); // return existe(nome, escopo) // ? varsNodes.Get(index.Get(nome + ":" + escopo)) // : _find(nome, escopo); // } // /** // * Auxiliar do metodo find // * // * @param nome // * @param escopo // * @return // */ // protected static Node _find(String nome, String escopo) { // nome = baseName(nome); // String[] escopos = escopo.split(",", 2); // if (escopos.length == 2) { // return find(nome, escopos[1]); // } // return existe(nome, escopos[0]) // ? varsNodes.Get(index.Get(nome + ":" + escopos[0])) // : null; // } // /** // * Retorna o escopo onde a variavel foi declarada. // * // * @param nome // * @param escopo // * @return // */ // public static String declaracao(String nome, String escopo) { // nome = baseName(nome); // try { // existe(nome, escopo); // return escopo; // } catch (Exception e) { // return _declaracao(nome, escopo); // } // } // // /** // * Auxiliar do metodo declaracao. // * // * @param nome // * @param escopo // * @return // */ // protected static String _declaracao(String nome, String escopo) { // nome = baseName(nome); // try { // String[] escopos = escopo.split(",", 2); // if (escopos.length == 2) { // return declaracao(nome, escopos[1]); // } // existe(nome, escopos[0]); // return escopos[0]; // } catch (Exception e) { // return null; // } // } // public static void var(int cod, Node var) { // varsNodes.put(cod, var); // } public static String baseName(String text) { return clearName(text).split("\\.")[0]; } public static void print() { String str = "Variaveis\n"; for (Map.Entry entry : vars.entrySet()) { String varKey = entry.getKey(); Node value = entry.getValue(); str += "\n" + value; } System.out.println(str); } // /** // * Testa ocorrencia de uma variavel, verifica se a mesma existe e se o tipo // * corresponde com o esperado. // * // * @param current // * @param tipoEsperado // */ // public static boolean teste(Node current, String tipoEsperado) { // /*Verifica se existe declaracao da variavel*/ // String varpath = current.getText(); // existe(varpath, current.Get("escopo")); // //// if (Types.structAcesso(varpath)) { //// Types.validarAtribuicao(current); //// } // Node var = find(varpath, current.Get("escopo")); // if (!var.Get("tipo").equals(tipoEsperado)) { // return false; // } // return true; // // } // static String getFullName(Node param) { // System.out.println("\n\nFULL:" + param); // String indices = ""; // Node indicesNodes = param.encontre("indices"); // if (null != indicesNodes) { // for (Node ind : indicesNodes.filhos()) { // indices += "[" + ind.getText() + "]"; // } // } // return param.getText() + indices; // } // protected static void verificarIndices(ArrayList acessoIndices) { // for (Node indice : acessoIndices) { // if (!indice.IsNumber("value")) { // AnalizadorSemantico.testExist(indice); // } // } // } // public static void acessoMatrixIsValid(Node var) throws Exception { // String tipoParent = var.parent.Get("tipo"); // String atributo = ivannosysUtils.clearName(var.getText()); // int limit, acesso, i = 0; // // Node indices = var.encontre("indices"); // // /*Caso não seja acessado nenhum indice da matrix return*/ // if (null == indices) { // return; // } // // ArrayList acessoIndices = indices.filhos(); // // verificarIndices(acessoIndices); // // /*Se for declaração apenas verifica se indices são corretos*/ // if (var.igual("class", "dec::var")) { // return; // } // /*Se for acesso de uma variavel e possuir indices verificar se os mesmos estao dentro dos limites*/ // ArrayList decIndices; // boolean isAtributo = var.igual("class", "atributo"); // decIndices = isAtributo // ? Types.getIndices(var) : Variables.getIndices(var); // limit = decIndices.size(); // acesso = acessoIndices.size(); // //// if (acesso < limit) { //// throw new Exception(Api.getFormatedPosition(var) + " Matriz acesso invalido. " //// + "Quantidade de indices inferior ao da matriz"); //// } else //// System.out.println("VAR:" + var.getText() + ",limit:" + limit + ", acesso:" + acesso); // if (acesso > limit) { // throw new Exception(Api.getFormatedPosition(var) + " Matriz acesso invalido. " // + "Quantidade {" + acesso + "} de indices superior ao da matriz {" + limit + "} "); // } // if (decIndices.size() != 0) { // return; // } // // for (Node indice : acessoIndices) { // if (indice.IsNumber("value")) { // limit = Integer.parseInt(decIndices.Get(i)); // acesso = indice.GetInt("value"); // if (acesso >= limit || acesso < 0) { // throw new Exception("Acesso indevido a um array, limite {" // + (limit - 1) + "} enquanto a tentativa foi {" // + acesso + "} na posição {" + i + "}"); // // } // } // i++; // } // // Node attr = var.encontreByClass("atributo"); // if (null == attr) { // return; // } // if (!temAtributo(tipoParent, atributo)) { // throw new Exception(" Acessando atributo [" + atributo + "] não definido no tipo[" + tipoParent + "]"); // } // // acessoMatrixIsValid(attr); // // } // // public static ArrayList getIndices(Node var) { // Node declaracao = find(var); // ArrayList indices = new ArrayList<>(); // for (Node n : declaracao.encontre("indices").filhos()) { // indices.add(n.getText()); // } // return indices; // } // // public static boolean isMagica(String nome) { // return nome.matches("__.*__(\\[.*\\])*"); // } // /** // * Verfica se todos os indices do acesso são numericos // * // * @param var // * @return // */ // public static boolean todosIndicesNumericos(Node var) { // Node indices = var.encontre("indices"); // if (null != indices) { // for (Node n : indices.filhos()) { // if (!n.IsNumber("value")) { // return false; // } // } // } // Node atributo = var.encontreByClass("atributo"); // return (null != atributo) ? todosIndicesNumericos(atributo) : true; // } // // public static int tamanhoVetor(Node n) throws Exception { // Node indices = n.encontre("indices"); // int size = 1; // if (null != indices) { // for (Node indice : indices.filhos()) { // size *= indice.GetInt("value"); // } // } // return size; // } public static void List() { StringBuilder s = new StringBuilder(); Node v; String index, constant, Public; for (String var : vars.keySet()) { index = ""; constant = ""; v = vars.get(var); if (v.eq("constant", "true")) { constant = "constant"; } Public = v.eq("public", "true") ? "public" : "private"; for (Node i : v.childrens()) { index += "[" + i.getText() + "]"; } s.append("\t" + var + ": " + index + v.Get("type") + " [" + Public + " " + constant + "]\n"); } System.out.println("Vars:\n" + s.toString()); } public static String Type(String id) { Node var = Get(id); if (var == null) { return "undefined"; } return var.Get("type"); } public static int Shift(String id) throws Exception { Node var = Get(id); if (var == null) { return 0; } // System.out.println("Var Shift:" + id); String[] varparts = var.getText().split("\\."); String varname = varparts[varparts.length - 1]; String[] idparts = id.split(varname + "\\.?"); if (idparts.length == 2) { ArrayList path = new ArrayList<>(Arrays.asList(idparts[1].split("\\."))); // System.out.println("shift:" + var.Get("type") + "-" + path); return Types.Shift(var.Get("type"), path); } // Não é acesso a um atributo return 0; } } // Node attrib = getAtributo(tipoParent, atributo); // if (attrib.igual("matrix", "false")) { // throw new Exception("Atributo [" + atributo + "] não é matrix"); // return; // } // // int i = 0, limit, limitCall, acesso; // ArrayList tipoIndices = new ArrayList<>(); // // String atributo = ivannosysUtils.clearName(var.getText()); // boolean eDeclaracao = var.igual("class", "dec::var"); // if (!eDeclaracao) { // // if (!temAtributo(tipoParent, atributo)) { // throw new Exception(" Acessando atributo [" + atributo + "] não definido no tipo[" + tipoParent + "]"); // } // // Node attrib = getAtributo(tipoParent, atributo); // // if (attrib.igual("matrix", "false")) { // if (!acessoIndices.isEmpty()) { // throw new Exception("Atributo [" + atributo + "] não é matrix"); // } // return; // } // tipoIndices = attrib.encontre("indices").getChildrens(); // } // // for (Node indice : acessoIndices) { // if (!indice.eNumerico("value")) { // AnalizadorSemantico.testExist(indice); // continue; // } else if (!eDeclaracao) { // limit = tipoIndices.Get(i).GetInt("value"); // acesso = indice.GetInt("value"); // if (acesso >= limit || acesso < 0) { // throw new Exception("Acesso indevido a um array, limite {" // + (limit - 1) + "} enquanto a tentativa foi {" // + acesso + "} na posição {" + i + "}"); // // } // } // i++; // }