blob: 6d233a3a29c6d481869421ef26ab73cfb1e75dc7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008 University of Illinois at Urbana-Champaign and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* UIUC - Initial API and implementation
*******************************************************************************/
package org.eclipse.photran.internal.core.analysis.types;
import org.eclipse.photran.internal.core.parser.ASTBinaryExprNode;
import org.eclipse.photran.internal.core.parser.ASTComplexConstNode;
import org.eclipse.photran.internal.core.parser.ASTDblConstNode;
import org.eclipse.photran.internal.core.parser.ASTIntConstNode;
import org.eclipse.photran.internal.core.parser.ASTLogicalConstNode;
import org.eclipse.photran.internal.core.parser.ASTNestedExprNode;
import org.eclipse.photran.internal.core.parser.ASTOperatorNode;
import org.eclipse.photran.internal.core.parser.ASTRealConstNode;
import org.eclipse.photran.internal.core.parser.ASTStringConstNode;
import org.eclipse.photran.internal.core.parser.ASTUnaryExprNode;
import org.eclipse.photran.internal.core.parser.ASTVisitor;
import org.eclipse.photran.internal.core.parser.IExpr;
/**
* A type checker for Fortran programs.
* <p>
* <b>This is incomplete. It can't type check expressions containing function calls, for
* example.</b>
*
* @author Stoyan Gaydarov
*/
public class TypeChecker
{
private TypeChecker() {}
public static Type getTypeOf(IExpr expression)
{
return new TypingVisitor().getTypeOf(expression);
}
protected static class TypingVisitor extends ASTVisitor
{
protected Type topType;
public Type getTypeOf(IExpr expression)
{
expression.accept(this);
return topType == null ? Type.UNKNOWN : topType;
}
@Override
public void visitASTBinaryExprNode(ASTBinaryExprNode node)
{
Type lhsType = getTypeOf(node.getLhsExpr());
Type rhsType = getTypeOf(node.getRhsExpr());
ASTOperatorNode op = node.getOperator();
//there is no binary operation we can do
//unknown and anything = unknown
//error and anything = error
if( lhsType.equals(Type.UNKNOWN) || lhsType.equals(Type.TYPE_ERROR) ||
rhsType.equals(Type.UNKNOWN) || rhsType.equals(Type.TYPE_ERROR) ||
rhsType.equals(Type.VOID) || lhsType.equals(Type.VOID) )
{
topType = Type.TYPE_ERROR;
return;
}
// This is for + - * / and **
if(op.hasPowerOp() || op.hasDivideOp() ||
op.hasMinusOp() || op.hasPlusOp() || op.hasTimesOp())
{
topType = checkNumericOperations(lhsType, rhsType);
}
//This is for an AND, OR, EQV, and NEQV of logical operators
else if(op.hasAndOp() || op.hasOrOp() || op.hasEqvOp() || op.hasNeqvOp())
{
topType = checkLogicalComparisons(lhsType, rhsType);
}
else if(op.hasGeOp() || op.hasGtOp() ||
op.hasLeOp() || op.hasLtOp() || //SlashOp?
op.hasEqOp() || op.hasNeOp() || op.hasEqEqOp() )
{
topType = checkNumericComparison(lhsType, rhsType, op);
}
else if( op.hasConcatOp())
{
if(lhsType.equals(Type.CHARACTER) && lhsType.equals(rhsType))
topType = Type.CHARACTER;
else
topType = Type.UNKNOWN;
}
else //TODO anything else
topType = Type.UNKNOWN;
}
/**
* @param node
* @param lhsType
* @param rhsType
*/
private Type checkNumericOperations(Type lhsType, Type rhsType)
{
//if the left or right side are any of these then there is a type error
if ( lhsType.equals(Type.LOGICAL) || lhsType.equals(Type.CHARACTER) ||
rhsType.equals(Type.LOGICAL) || rhsType.equals(Type.CHARACTER) )
{
return Type.TYPE_ERROR;
}
//When the types are the same then the result is that type
if(lhsType.equals(rhsType))
{
return lhsType;
}
//When the first is an Integer
if (lhsType.equals(Type.INTEGER) )
{
return checkIntegerOperations(rhsType);
}
//When the first is a Real
else if ( lhsType.equals(Type.REAL) )
{
return checkRealOperations(rhsType);
}
//When the first is a Complex
else if ( lhsType.equals(Type.COMPLEX) )
{
return checkComplexComparison(rhsType);
}
//When the first is a Double Precision
else if ( lhsType.equals(Type.DOUBLEPRECISION ))
{
return checkDoubleComparison(rhsType);
}
else
return Type.UNKNOWN;
}
/**
* @param node
* @param rhsType
*/
private Type checkComplexComparison(Type rhsType)
{
if(rhsType.equals(Type.INTEGER) || rhsType.equals(Type.REAL) || rhsType.equals(Type.DOUBLEPRECISION))
return Type.COMPLEX;
else
return Type.UNKNOWN;
}
/**
* @param node
* @param rhsType
*/
private Type checkDoubleComparison(Type rhsType)
{
if (rhsType.equals(Type.INTEGER) || rhsType.equals(Type.REAL))
return Type.DOUBLEPRECISION;
else if(rhsType.equals(Type.COMPLEX))
return Type.COMPLEX;
else
return Type.UNKNOWN;
}
/**
* @param node
* @param rhsType
*/
private Type checkRealOperations(Type rhsType)
{
if (rhsType.equals(Type.INTEGER))
return Type.REAL;
else if(rhsType.equals(Type.DOUBLEPRECISION))
return Type.DOUBLEPRECISION;
else if(rhsType.equals(Type.COMPLEX))
return Type.COMPLEX;
else
return Type.UNKNOWN;
}
/**
* @param node
* @param rhsType
*/
private Type checkIntegerOperations(Type rhsType)
{
if(rhsType.equals(Type.REAL))
return Type.REAL;
else if(rhsType.equals(Type.COMPLEX))
return Type.COMPLEX;
else if(rhsType.equals(Type.DOUBLEPRECISION))
return Type.DOUBLEPRECISION;
else
return Type.UNKNOWN;
}
/**
* @param node
* @param lhsType
* @param rhsType
*/
private Type checkLogicalComparisons(Type lhsType, Type rhsType)
{
if( lhsType.equals(Type.LOGICAL) && rhsType.equals(Type.LOGICAL))
return Type.LOGICAL;
else
return Type.TYPE_ERROR;
}
/**
* @param node
* @param lhsType
* @param rhsType
*/
private Type checkNumericComparison(Type lhsType, Type rhsType, ASTOperatorNode op)
{
//you can't do this kind of comparison on logical and character types
if ( lhsType.equals(Type.LOGICAL) || lhsType.equals(Type.CHARACTER) ||
rhsType.equals(Type.LOGICAL) || rhsType.equals(Type.CHARACTER) )
{
//System.out.println(lhsType + "\t::\t" + rhsType);
return Type.TYPE_ERROR;
}
//Complex only has == and /=
else if(lhsType.equals(Type.COMPLEX) || rhsType.equals(Type.COMPLEX))
{
if(op.hasEqEqOp() || op.hasEqOp() || op.hasNeOp()) //remove EqEq
return Type.LOGICAL;
else
return Type.TYPE_ERROR;
}
//All the remaining cases are ok
else
return Type.LOGICAL;
}
@Override
public void visitASTIntConstNode(ASTIntConstNode node)
{
topType = Type.INTEGER;
}
@Override
public void visitASTDblConstNode(ASTDblConstNode node)
{
topType = Type.DOUBLEPRECISION;
}
@Override
public void visitASTLogicalConstNode(ASTLogicalConstNode node)
{
topType = Type.LOGICAL;
}
@Override
public void visitASTNestedExprNode(ASTNestedExprNode node)
{
topType = getTypeOf(node.getExpr());
}
@Override
public void visitASTRealConstNode(ASTRealConstNode node)
{
topType = Type.REAL;
}
@Override
public void visitASTStringConstNode(ASTStringConstNode node)
{
topType = Type.CHARACTER;
}
@Override
public void visitASTComplexConstNode(ASTComplexConstNode node)
{
topType = Type.COMPLEX;
}
@Override
public void visitASTUnaryExprNode(ASTUnaryExprNode node)
{
Type operand = getTypeOf(node.getOperand());
ASTOperatorNode operator = node.getOperator();
//character has no unary operations
if(operand.equals(Type.CHARACTER))
topType = Type.TYPE_ERROR;
// .NOT. only applies to logical
else if(operator != null && operator.hasNotOp() )
{
if(operand.equals(Type.LOGICAL))
topType = Type.LOGICAL;
else
topType = Type.TYPE_ERROR;
}
//logical has no other unary operations
else if(operand.equals(Type.LOGICAL))
topType = Type.TYPE_ERROR;
//the type of the expression is the same as the operand
else
topType = operand;
}
}
}