package zinara.semantic; import java.util.ArrayList; import zinara.ast.expression.Expression; import zinara.ast.expression.BooleanExp; import zinara.ast.expression.IntegerExp; import zinara.ast.expression.LValue; import zinara.ast.expression.LValueList; import zinara.ast.expression.LValueTuple; import zinara.ast.expression.LValueDict; import zinara.ast.expression.LValueVariant; import zinara.ast.expression.Identifier; import zinara.ast.expression.FunctionCall; import zinara.ast.instructions.CodeBlock; import zinara.ast.instructions.Instruction; import zinara.ast.instructions.Return; import zinara.ast.instructions.ProcedureCall; import zinara.ast.instructions.SetVariant; import zinara.ast.type.Type; import zinara.ast.type.DictType; import zinara.ast.type.IntType; import zinara.ast.type.ListType; import zinara.ast.type.TupleType; import zinara.ast.type.FunctionType; import zinara.ast.type.ProcedureType; import zinara.ast.type.VariantType; import zinara.exceptions.IdentifierNotDeclaredException; import zinara.exceptions.InvalidAccessException; import zinara.exceptions.InvalidInstructionException; import zinara.exceptions.InvalidVariantException; import zinara.exceptions.KeyErrorException; import zinara.exceptions.TypeClashException; import zinara.symtable.*; public class StaticTypeChecking { public static boolean compareTypes(Type type1, Type type2) { return (type1 == type2); } /* Checks if a given expression is of a given type */ //@ requires expr != null; //@ requires type != null; public static void checkExpression(Expression expr, Type type) throws TypeClashException { if (!type.equals(expr.getType())) throw new TypeClashException("Conflicto de tipos en la expresion " + expr + ". Se espera " + type + " y se obtuvo " + expr.getType()); } /* Checks if a given expression is instance of a given type */ // requires expr != null; // requires type != null; // public static void checkExpressionSoft(Expression expr, Type type) // throws TypeClashException { // if (!( expr.getType() instanceof typeClass )) // throw new TypeClashException("Conflicto de tipos en la expresion " + expr + ". Se espera " + type + " y se obtuvo " + expr.getType()); // } /* Checks if a given expression is instance of a given type */ //@ requires expr != null; public static void checkIterable(Expression expr) throws TypeClashException { if (!(expr.getType().getType() instanceof ListType)) throw new TypeClashException("La expresion " + expr + expr.getType() + " no es iterable."); } /* Checks two things: 1. the return statement only can be inside of a function. If it's not then throw an InvalidInstructionException 2. the expression after the return statement is the same type of the defined function */ //@ requires expr != null; //@ requires st != null; public static Return checkReturnValue(Expression expr, SymTable st) throws TypeClashException, InvalidInstructionException { SymValue idSymValue = st.getSymValueForId("return"); if (idSymValue != null) { // we're inside a funtion if (idSymValue.getType() == null) throw new InvalidInstructionException("Instruccion `return` no permitida en un procedimiento"); else if (expr.getType().equals(idSymValue.getType())) return new Return(expr); else throw new TypeClashException("Tipo de retorno de la funcion " + idSymValue.getType() + " difiere del tipo de la expresion " + expr); } else throw new InvalidInstructionException("Instruccion `return` no permitida en el main"); } /* The return statement has to be at least once inside the codeblock */ public static void checkReturnStatement(String funcName, CodeBlock code) throws InvalidInstructionException { boolean found = false; Instruction inst; for (int i = 0; i < code.getBlock().size(); i++) { inst = (Instruction)code.getBlock().get(i); found = found || (inst instanceof Return); } if (!found) throw new InvalidInstructionException("La funci�n " + funcName + " no tiene return"); } public static FunctionCall checkFunctionCall(String funcName, ArrayList expr_list, SymTable st) throws TypeClashException, IdentifierNotDeclaredException, InvalidAccessException { SymValue idSymValue = st.getSymValueForIdOrDie(funcName); if (!(idSymValue.getType() instanceof FunctionType)) throw new TypeClashException("El identificador " + funcName + " tiene tipo " + idSymValue.getType() + ", no es una funcion"); FunctionType funcType = (FunctionType)idSymValue.getType(); // Check every argument Expression currentExpr; for (int i = 0; i < expr_list.size(); i++) { currentExpr = (Expression)expr_list.get(i); if (!currentExpr.getType().equals(funcType.getArgumentType(i))) throw new TypeClashException("El tipo de la expresion " + currentExpr + " difiere del tipo del argumento " + (i+1) + " de la funcion " + funcName); if (funcType.isArgumentByRef(i) && !(currentExpr instanceof LValue)) throw new InvalidAccessException("La expresion " + currentExpr + " no puede ser pasada como parametro por referencia"); } return new FunctionCall(funcName, expr_list, st); } public static ProcedureCall checkProcedureCall(String procName, ArrayList expr_list, SymTable st) throws TypeClashException, IdentifierNotDeclaredException, InvalidAccessException { SymValue idSymValue = st.getSymValueForIdOrDie(procName); if (!(idSymValue.getType() instanceof ProcedureType)) throw new TypeClashException("El identificador " + procName + " no es un procedimiento"); ProcedureType procType = (ProcedureType)idSymValue.getType(); // Check every argument Expression currentExpr; for (int i = 0; i < expr_list.size(); i++) { currentExpr = (Expression)expr_list.get(i); if (!currentExpr.getType().equals(procType.getArgumentType(i))) throw new TypeClashException("El tipo de la expresion " + currentExpr + " difiere del tipo del argumento " + (i+1) + " de la funcion " + procName); if (procType.isArgumentByRef(i) && !(currentExpr instanceof LValue)) throw new InvalidAccessException("La expresion " + currentExpr + " no puede ser pasada como parametro por referencia"); } return new ProcedureCall(procName, expr_list, st); } /* Checks if some lvalue is well-constructed, this work only for Lists or Tuples, the Dictionary checking is on the next static method. */ public static LValue checkAndReturnLValue(LValue constructor, Expression expr) throws InvalidAccessException, TypeClashException, KeyErrorException { Type constructorType = constructor.getType().getType(); if (!(constructorType instanceof TupleType) && !(constructorType instanceof ListType)) throw new InvalidAccessException("La expresion " + constructor + " no es del tipo lista o tupla y no puede ser indexada con una expresion. "); if (constructorType instanceof ListType) if (!(expr.getType() instanceof IntType)) throw new InvalidAccessException("La expresion " + expr + " es del tipo " + expr.getType() + " pero debe ser del tipo Int para poder realizar el indexamiento"); else return new LValueList(constructor, expr); if (constructorType instanceof TupleType) if (!(expr.getType() instanceof IntType)) throw new InvalidAccessException("La expresion " + expr + " es del tipo " + expr.getType() + " pero debe ser del tipo Int para poder realizar el indexamiento"); else if (!expr.isStaticallyKnown()) throw new InvalidAccessException("La expresion " + expr + " debe ser un entero literal"); else { System.out.println("IS STATICALLY KNOWN " + expr + ":" + expr.staticValue()); return new LValueTuple(constructor, ((Integer)expr.staticValue()).intValue()); } throw new InvalidAccessException("Diccionarios todavia no estan implementados"); } //@requires constructor != null; //@requires id != null; //@requires ct != null; public static LValue checkAndReturnLValue(LValue constructor, String id, SymTable ct) throws InvalidAccessException, TypeClashException, KeyErrorException, IdentifierNotDeclaredException { Type constructorType = constructor.getType().getType(); //@assume constructor.getType() != null; // if (constructorType instanceof ListType) { // SymTable st = ct.getSymTableForId(id); // if (st == null) throw new IdentifierNotDeclaredException(id); // SymValue sv = st.getSymValueForId(id); // //@assume sv != null; // if (sv.getType() instanceof IntType) // return new LValueList(constructor, new Identifier(id, st)); // else // throw new InvalidAccessException("El identificador " + id + " tiene tipo " + sv.getType() + ", se requiere Int"); // } if (!(constructorType instanceof DictType) && !(constructorType instanceof VariantType)) throw new InvalidAccessException("La expresion " + constructor + " no representa un diccionario o una variante y no puede ser indexado con un identificador."); if (constructorType instanceof DictType) return new LValueDict(constructor, id); else return new LValueVariant(constructor, id); } public static int returnStaticInt(Expression expr) throws TypeClashException { // Checks if the expression is statically known, and if it is, // check if it's an integer.. if (!(expr.getType() instanceof IntType)) throw new TypeClashException("La expresion es de tipo " + expr.getType() + " y es necesario que sea de tipo <INT> para ser tamano de una lista"); if (!expr.isStaticallyKnown()) throw new TypeClashException("La expresion " + expr + " no puede ser calculada a tiempo de compilaci�n"); Object s = expr.staticValue(); if (!(s instanceof Integer)) throw new TypeClashException("La expresion " + expr + " no pudo ser reducida a un entero"); return ((Integer)s).intValue(); } public static SetVariant checkVariantChange(LValue lv, String var) throws TypeClashException, InvalidVariantException { Type lvType = lv.getType().getType(); if (!(lvType instanceof VariantType)) throw new InvalidVariantException("El identificador " + lv + " no es una variante"); if (((VariantType)lvType).getVariant(var) == null) throw new InvalidVariantException("El identificador " + lv + " no tiene una variante con nombre " + var); return new SetVariant(lv, var); } }