class DrlxParseUtil {

    public static java.lang.reflect.Type getExpressionType(RuleContext context, TypeResolver typeResolver, Expression expr, Collection<String> usedDeclarations) {
        if (expr instanceof LiteralExpr) {
            return getLiteralExpressionType( ( LiteralExpr ) expr );
        }

        if (expr instanceof UnaryExpr) {
            return getExpressionType(context, typeResolver, expr.asUnaryExpr().getExpression(), usedDeclarations);
        }

        if (expr instanceof ArrayAccessExpr) {
            return getClassFromContext(typeResolver, ((ArrayCreationExpr)((ArrayAccessExpr) expr).getName()).getElementType().asString());
        }

        if (expr instanceof ArrayCreationExpr) {
            return getClassFromContext(typeResolver, ((ArrayCreationExpr) expr).getElementType().asString());
        }

        if (expr instanceof MapCreationLiteralExpression) {
            return Map.class;
        }

        if (expr instanceof NameExpr) {
            return expressionTypeNameExpr(context, usedDeclarations, ((NameExpr) expr).getNameAsString());
        }
        if (expr instanceof DrlNameExpr) {
            return expressionTypeNameExpr(context, usedDeclarations, ((DrlNameExpr) expr).getNameAsString());
        }

        if (expr instanceof BinaryExpr) {
            return boolean.class;
        }

        if (expr instanceof MethodCallExpr) {
            MethodCallExpr methodCallExpr = ( MethodCallExpr ) expr;
            Optional<Expression> scopeExpression = methodCallExpr.getScope();
            if (scopeExpression.isPresent()) {
                java.lang.reflect.Type scopeType = getExpressionType(context, typeResolver, scopeExpression.get(), usedDeclarations);
                return returnTypeOfMethodCallExpr(context, typeResolver, methodCallExpr, scopeType, usedDeclarations);
            } else {
                throw new IllegalStateException("Scope expression is not present for " + ((MethodCallExpr) expr).getNameAsString() + "!");
            }
        }

        if (expr instanceof ObjectCreationExpr) {
            final ClassOrInterfaceType type = ((ObjectCreationExpr) expr).getType();
            return getClassFromContext (typeResolver, type.asString());
        }

        if (expr.isCastExpr()) {
            String typeName = expr.asCastExpr().getType().toString();
            try {
                return typeResolver.resolveType( expr.asCastExpr().getType().toString() );
            } catch (ClassNotFoundException e) {
                context.addCompilationError( new InvalidExpressionErrorResult( "Unknown type in cast expression: " + typeName ) );
                throw new RuntimeException( "Unknown type in cast expression: " + typeName );
            }
        }

        if (expr instanceof ConditionalExpr) {
            ConditionalExpr ternaryExpr = (( ConditionalExpr ) expr);
            java.lang.reflect.Type conditionType = getExpressionType( context, typeResolver, ternaryExpr.getCondition(), usedDeclarations );
            if (conditionType != Boolean.class && conditionType != boolean.class) {
                context.addCompilationError( new InvalidExpressionErrorResult( "Condtion used in ternary expression '" + expr + "' isn't boolean" ) );
                return Object.class;
            }

            java.lang.reflect.Type leftType = getExpressionType( context, typeResolver, ternaryExpr.getThenExpr(), usedDeclarations );
            java.lang.reflect.Type rightType = getExpressionType( context, typeResolver, ternaryExpr.getElseExpr(), usedDeclarations );
            Class<?> leftClass = toRawClass( leftType );
            Class<?> rightClass = toRawClass( rightType );
            if (leftClass.isAssignableFrom( rightClass )) {
                return leftType;
            }
            if (rightClass.isAssignableFrom( leftClass )) {
                return rightType;
            }
            return Object.class;
        }

        throw new RuntimeException("Unknown expression type: " + PrintUtil.printConstraint(expr));
    }

    private  DrlxParseUtil();

}