TypeBuilder.java

package edu.udel.cis.vsl.tass.ast2model.impl;

import java.util.HashMap;
import java.util.Map;

import edu.udel.cis.vsl.tass.ast.IF.ASTNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.AbstractSyntaxTreeIF;
import edu.udel.cis.vsl.tass.ast.IF.IdentifierNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.PairNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.SequenceNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.type.ArrayTypeNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.type.BooleanTypeNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.type.CharacterTypeNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.type.CompositeTypeNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.type.EnumerationTypeNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.type.FunctionTypeNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.type.IntegerTypeNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.type.PointerTypeNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.type.RealTypeNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.type.TypeNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.type.TypeReferenceNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.type.VoidTypeNodeIF;
import edu.udel.cis.vsl.tass.ast2model.IF.TypeBuilderIF;
import edu.udel.cis.vsl.tass.model.IF.ModelFactoryIF;
import edu.udel.cis.vsl.tass.model.IF.SyntaxException;
import edu.udel.cis.vsl.tass.model.IF.expression.ExpressionIF;
import edu.udel.cis.vsl.tass.model.IF.type.ArrayTypeIF;
import edu.udel.cis.vsl.tass.model.IF.type.PointerTypeIF;
import edu.udel.cis.vsl.tass.model.IF.type.TypeIF;

public class TypeBuilder implements TypeBuilderIF {

	ModelFactoryIF factory;

	Map<TypeNodeIF, TypeIF> typeMap = new HashMap<TypeNodeIF, TypeIF>();

	/**
	 * A TypeBuilder is used by the ModelBuilder to create and keep track of
	 * model types associated with each AST type. The ModelFactoryIF argument
	 * should be the same ModelFactoryIF used by the ModelBuilder.
	 */
	public TypeBuilder(ModelFactoryIF factory) {
		this.factory = factory;
	}

	@Override
	public void buildTypes(AbstractSyntaxTreeIF ast) throws SyntaxException {
		addTypes(ast.rootNode());
	}

	@Override
	public TypeIF getModelType(TypeNodeIF astType) throws SyntaxException {
		if (!typeMap.containsKey(astType))
			processType(astType);
		return typeMap.get(astType);
	}

	private void addTypes(ASTNodeIF node) throws SyntaxException {
		if (node instanceof TypeNodeIF) {
			processType((TypeNodeIF) node);
		} else {
			for (int i = 0; i < node.numChildren(); i++) {
				addTypes(node.child(i));
			}
		}
	}

	/**
	 * Takes an AST type node and creates a new model node for the type. Should
	 * only be used on an AST type node that is not already in typeMap.
	 * 
	 * @throws SyntaxException
	 *             if the type is unknown.
	 */
	private void processType(TypeNodeIF node) throws SyntaxException {
		// Already have this type, so return
		if (typeMap.containsKey(node)) {
			return;
		}
		if (node instanceof ArrayTypeNodeIF) {
			ArrayTypeNodeIF astArrayType = (ArrayTypeNodeIF) node;
			int dimensions = 1;

			// "Flatten" the array to a single multi-dimensional array
			while (astArrayType.elementType() instanceof ArrayTypeNodeIF) {
				astArrayType = (ArrayTypeNodeIF) astArrayType.elementType();
				dimensions++;
			}
			typeMap.put(node, factory.arrayType(
					getModelType(astArrayType.elementType()), dimensions));
		} else if (node instanceof BooleanTypeNodeIF) {
			typeMap.put(node, factory.booleanType());
		} else if (node instanceof CharacterTypeNodeIF) {
			typeMap.put(node, factory.characterType());
		} else if (node instanceof CompositeTypeNodeIF) {
			CompositeTypeNodeIF compositeTypeNode = (CompositeTypeNodeIF) node;
			String name = compositeTypeNode.name().name();
			SequenceNodeIF<PairNodeIF<IdentifierNodeIF, TypeNodeIF>> fields = compositeTypeNode
					.fields();
			String[] fieldNames = new String[fields.numChildren()];
			TypeIF[] fieldTypes = new TypeIF[fields.numChildren()];
			ExpressionIF[][] dimensionExpressions = new ExpressionIF[fields
					.numChildren()][];

			for (int i = 0; i < fields.numChildren(); i++) {
				fieldNames[i] = fields.getSequenceChild(i).left().name();
				fieldTypes[i] = getModelType(fields.getSequenceChild(i).right());
				if (fieldTypes[i] instanceof ArrayTypeIF) {
					dimensionExpressions[i] = new ExpressionIF[((ArrayTypeIF) fieldTypes[i])
							.dimension()];
					// TODO: Do we need to figure out concrete dimension
					// expressions? Where do these come from in the AST?
				} else {
					dimensionExpressions[i] = null;
				}
			}
			typeMap.put(node, factory.recordType(name, fieldNames, fieldTypes, dimensionExpressions));
		} else if (node instanceof EnumerationTypeNodeIF) {

		} else if (node instanceof FunctionTypeNodeIF) {

		} else if (node instanceof IntegerTypeNodeIF) {
			// One of the integer types is CHAR. Use the model character type
			// for this.
			if (((IntegerTypeNodeIF) node).intType() == IntegerTypeNodeIF.IntType.CHAR) {
				typeMap.put(node, factory.characterType());
			} else {
				typeMap.put(node, factory.integerType());
			}
		} else if (node instanceof PointerTypeNodeIF) {
			TypeNodeIF astBaseType = ((PointerTypeNodeIF) node).baseType();
			TypeIF baseType = typeMap.get(astBaseType);
			TypeIF result;

			if (baseType != null) {
				result = factory.pointerType(baseType);
			} else {
				// cyclic resolution...
				result = factory.newPointerType();
				typeMap.put(node, result);
				processType(astBaseType);
				baseType = getModelType(astBaseType);
				result = factory.setBaseType((PointerTypeIF) result, baseType);
			}

			typeMap.put(node, factory.pointerType(baseType));
		} else if (node instanceof RealTypeNodeIF) {
			typeMap.put(node, factory.rationalType());
		} else if (node instanceof TypeReferenceNodeIF) {
			processType(((TypeReferenceNodeIF) node).referent().type());
		} else if (node instanceof VoidTypeNodeIF) {
			typeMap.put(node, factory.voidType());
		} else {
			throw new SyntaxException(node, "Unknown type: " + node);
		}
		// TODO Auto-generated method stub

	}

}