package de.skuzzle.polly.core.parser.ast.expressions; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import de.skuzzle.polly.core.parser.Position; import de.skuzzle.polly.core.parser.ast.Node; import de.skuzzle.polly.core.parser.ast.declarations.types.Substitution; import de.skuzzle.polly.core.parser.ast.declarations.types.Type; import de.skuzzle.polly.core.parser.ast.visitor.ASTTraversalException; import de.skuzzle.polly.core.parser.ast.visitor.Transformation; import de.skuzzle.polly.tools.Equatable; /** * Super class for all expression Nodes in the AST. When types are resolved, every * expression may get assigned several possible types (due to function overloading). * In a second step, the {@link TypeResolver} tries to figure out a unique type for each * expression. If this is not possible, a type error occurs. * * @author Simon Taddiken */ public abstract class Expression extends Node { private Type unique; private final List<Type> types; private final Map<Type, Substitution> constraints; /** * Creates a new Expression with given {@link Position} and unique {@link Type}. * * @param position Position within the input String of this expression. * @param unique Type of this expression. */ public Expression(Position position, Type unique) { super(position); this.unique = unique; this.types = new ArrayList<Type>(); this.constraints = new HashMap<Type, Substitution>(); if (unique != Type.UNKNOWN) { this.types.add(unique); } } /** * Creates a new Expression with given {@link Position} and unknown type. * * @param position Position within the input String of this expression. */ public Expression(Position position) { this(position, Type.UNKNOWN); } /** * Whether this is a problem node. Default value is <code>false</code>. * * @return Whether this is a problem node. */ public boolean isProblem() { return false; } /** * Gets a list of all possible types for this expression. You should never modify the * returned list directly. Use {@link #addType(Type)} and * {@link #addTypes(Collection)} to add possible types to this list. * * @return List of possible types of this expression. */ public List<Type> getTypes() { return this.types; } /** * Adds another type as possible type for this expression. If an instance of that * type is already contained in the type list, the latter call will be ignored. * * @param type Possible type of this expression. * @return Whether the type has been added. */ public boolean addType(Type type) { return this.addType(type, null); } public boolean addType(Type type, Substitution constraint) { for (final Type t : this.types) { if (Type.tryUnifyNoInheritance(type, t)) { return false; } } this.types.add(type); this.constraints.put(type, constraint); return true; } public boolean hasConstraint(Type type) { return this.constraints.get(type) != null; } public Substitution getConstraint(Type type) { return this.constraints.get(type); } /** * Adds all the types from the given collection as possible type for this * expression. Types for which an instance already exists in this expression's type * list, will be ignored. * * <p>This method simply calls {@link #addType(Type)} for each type in * the given collection.</p> * @param types Types to add as possible type for this expression. */ public void addTypes(Collection<? extends Type> types) { for (final Type type : types) { this.addType(type); } } /** * Clears the current list of types, then adds every type of the given list using * {@link #addTypes(Collection)}. * * @param types The new collection of types for this expression. */ public void setTypes(Collection<Type> types) { this.types.clear(); this.addTypes(types); } /** * Gets whether the type of this expression was already resolved. * * @return <code>true</code> if the type of this expression is not * {@link Type#UNKNOWN}. */ public boolean typeResolved() { return this.getUnique() != Type.UNKNOWN; } /** * Gets the single resolved {@link Type} of this expression. If it has not yet been * resolved, it will be {@link Type#UNKNOWN}. * * @return The type. */ public Type getUnique() { return this.unique; } /** * Sets the unique type of this expression. * * @param unique The new type. */ public void setUnique(Type unique) { this.unique = unique; } @Override public Class<?> getEquivalenceClass() { return Expression.class; } @Override public boolean actualEquals(Equatable o) { final Expression other = (Expression) o; return this.getUnique().equals(other.getUnique()); } @Override public String toString() { return "unique: " + this.unique + ", types: " + this.types; } @Override public abstract Expression transform(Transformation transformation) throws ASTTraversalException; }