package zinara.semantic;
import java.util.HashMap;
import java.util.Iterator;
import zinara.ast.type.*;
import zinara.exceptions.TypeClashException;
import zinara.parser.sym;
/*
Does type cohersion and simple operator's type checking
*/
public class Operators {
private class OP {
int operator;
Type rightType;
Type leftType;
public OP(int o, Type l, Type r) { this.operator = o; this.leftType = l; this.rightType = r; }
//@ requires other != null;
public boolean equals(OP other) {
return (this.leftType.equals(other.leftType)) && (this.rightType.equals(other.rightType)) && (this.operator == other.operator);
}
public int hashCode() {
String hash;
if (rightType != null)
hash = leftType.getType().toString() + operator + rightType.getType().toString();
else
hash = leftType.getType().toString() + operator;
return Math.abs(hash.hashCode());
}
public String toString() {
if (rightType != null)
return leftType.getType().toString() + operator + rightType.getType().toString();
else
return leftType.getType().toString() + operator;
}
}
public HashMap table; //@invariant table != null;
public final int arithmetic = -1;
public final int relational = -2;
public final int logical = -3;
public final int unary = -4;
public final int cast = -5;
public Operators() {
this.table = new HashMap();
/*
Binary Operators
*/
// Arithmetic
this.table.put(new OP(this.arithmetic, new IntType(), new IntType()).toString(), new IntType()); // new IntType() -> new IntType()
this.table.put(new OP(this.arithmetic, new FloatType(), new FloatType()).toString(), new FloatType());
this.table.put(new OP(this.arithmetic, new IntType(), new FloatType()).toString(), new FloatType());
this.table.put(new OP(this.arithmetic, new FloatType(), new IntType()).toString(), new FloatType());
//this.table.put(new OP(sym.PLUS, new CharType(), new CharType()), STRING);
// Relational
this.table.put(new OP(this.relational, new IntType(), new IntType()).toString(), new BoolType());
this.table.put(new OP(this.relational, new FloatType(), new FloatType()).toString(), new BoolType());
//this.table.put(new OP(this.relational, new CharType(), new CharType()).toString(), new BoolType());
this.table.put(new OP(this.relational, new BoolType(), new BoolType()).toString(), new BoolType());
this.table.put(new OP(this.relational, new IntType(), new FloatType()).toString(), new BoolType());
this.table.put(new OP(this.relational, new FloatType(), new IntType()).toString(), new BoolType());
// Logical
//this.table.put(new OP(this.logical, new IntType(), new IntType()).toString(), new BoolType());
//this.table.put(new OP(this.logical, new FloatType(), new FloatType()).toString(), new BoolType());
this.table.put(new OP(this.logical, new BoolType(), new BoolType()).toString(), new BoolType());
//this.table.put(new OP(this.logical, new IntType(), new FloatType()).toString(), new BoolType());
//this.table.put(new OP(this.logical, new FloatType(), new IntType()).toString(), new BoolType());
/*
Unary Operators
*/
this.table.put(new OP(sym.NOT, new IntType(), null).toString(), new BoolType());
this.table.put(new OP(sym.NOT, new FloatType(), null).toString(), new BoolType());
this.table.put(new OP(sym.NOT, new BoolType(), null).toString(), new BoolType());
this.table.put(new OP(sym.UMINUS, new IntType(), null).toString(), new IntType());
this.table.put(new OP(sym.UMINUS, new FloatType(), null).toString(), new FloatType());
//Casting
//El 2do argumentdo del constructor de OP es el tipo HACIA el que se castea
this.table.put(new OP(this.cast, new IntType(), new FloatType()).toString(), new FloatType());
this.table.put(new OP(this.cast, new FloatType(), new IntType()).toString(), new IntType());
}
// also returns the type cohersion if needed
public Type check(int o, Type l, Type r) throws TypeClashException {
// maps the operator to `arithmetic`, `relational`, `logical` or `cast`
int om = -1;
switch (o) {
case sym.PLUS:
case sym.MINUS:
case sym.TIMES:
case sym.DIVIDE:
case sym.MOD:
case sym.POW:
om = arithmetic;
break;
case sym.GT:
case sym.LT:
case sym.GTE:
case sym.LTE:
case sym.SHEQ:
case sym.DEEQ:
case sym.NOEQ:
om = relational;
break;
case sym.AND:
case sym.OR:
case sym.SAND:
case sym.SOR:
om = logical;
break;
default:
om = o;
break;
}
String comp = new OP(om,l,r).toString();
//@ assume \typeof(table.get(comp)) == \type(Type);
if (!table.containsKey(comp)) throw new TypeClashException("Error de tipos con el operador " + o + " en la linea tal..."); // mejorar
Type result = (Type)table.get(comp);
return result;
}
}