package org.dcache.util.expression;
import static org.dcache.util.expression.Type.*;
/**
* Type checker and annotator for expressions.
*/
public class TypeChecker
{
private final SymbolTable _symbols;
public TypeChecker(SymbolTable symbols)
{
_symbols = symbols;
}
private Type ensureSame(Type actual, Type expected)
throws TypeMismatchException
{
if (actual != expected) {
throw new TypeMismatchException("Type mismatch: Expected " + expected + ", but found " + actual);
}
return actual;
}
public void check(Expression expression, Type expected)
throws TypeMismatchException, UnknownIdentifierException
{
ensureSame(check(expression), expected);
}
public Type check(Expression expression)
throws TypeMismatchException, UnknownIdentifierException
{
switch (expression.getToken()) {
case NUMBER_LITERAL:
expression.setType(DOUBLE);
break;
case STRING_LITERAL:
expression.setType(STRING);
break;
case IDENTIFIER:
String identifier = expression.getString();
Symbol symbol = _symbols.get(identifier);
if (symbol == null) {
throw new UnknownIdentifierException(identifier);
}
expression.setType(symbol.getType());
break;
case TRUE:
expression.setType(BOOLEAN);
break;
case FALSE:
expression.setType(BOOLEAN);
break;
case IF:
ensureSame(check(expression.get(0)), BOOLEAN);
expression.setType(ensureSame(check(expression.get(1)),
check(expression.get(2))));
break;
case EQ:
case NE:
ensureSame(check(expression.get(0)),
check(expression.get(1)));
expression.setType(BOOLEAN);
break;
case AND:
case OR:
ensureSame(check(expression.get(0)), BOOLEAN);
ensureSame(check(expression.get(1)), BOOLEAN);
expression.setType(BOOLEAN);
break;
case NOT:
ensureSame(check(expression.get(0)), BOOLEAN);
expression.setType(BOOLEAN);
break;
case UMINUS:
ensureSame(check(expression.get(0)), DOUBLE);
expression.setType(DOUBLE);
break;
case LT:
case LE:
case GT:
case GE:
ensureSame(check(expression.get(0)), DOUBLE);
ensureSame(check(expression.get(1)), DOUBLE);
expression.setType(BOOLEAN);
break;
case MINUS:
case PLUS:
case MULT:
case DIV:
case MOD:
case POWER:
ensureSame(check(expression.get(0)), DOUBLE);
ensureSame(check(expression.get(1)), DOUBLE);
expression.setType(DOUBLE);
break;
case MATCH:
case NOT_MATCH:
ensureSame(check(expression.get(0)), STRING);
ensureSame(check(expression.get(1)), STRING);
expression.setType(BOOLEAN);
break;
}
return expression.getType();
}
}