package de.skuzzle.polly.core.parser.ast.declarations.types; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; /** * This class represents a mapping of type variables to other type expressions. * @author Simon Taddiken */ public class Substitution { /** Unmodifiable empty substitution. */ public final static Substitution EMPTY = new Substitution( Collections.<TypeVar, Type>emptyMap()); /** * Creates a substitution that will replace all variables in the type expression * it is applied to with new ones. The newly created variables get a reference to * the variables they were created from. * * @return A new substitution. */ public final static Substitution fresh() { return new Substitution() { @Override public Type getSubstitute(TypeVar v) { Type te = this.mappings.get(v); if (te == null) { te = Type.newTypeVar(); ((TypeVar) te).source = v; this.mappings.put(v, te); } return te; } }; } /** Substitution mappings in this instance */ protected final Map<TypeVar, Type> mappings; /** * Creates a new substitution from the given mapping. * * @param mappings Mapping of type variables to type expressions. */ public Substitution(Map<TypeVar, Type> mappings) { this.mappings = mappings; } /** * Creates a new empty substitution. */ public Substitution() { this(new HashMap<TypeVar, Type>()); } /** * Applies the given substitution to this one, creating a new {@link Substitution} * instance. * * @param s The substitution to apply. * @return A new {@link Substitution} instance. */ public Substitution subst(Substitution s) { final Substitution result = new Substitution( new HashMap<TypeVar, Type>()); for (final Entry<TypeVar, Type> e : this.mappings.entrySet()) { final Type substitute = s.getSubstitute(e.getKey()); result.mappings.put(e.getKey(), substitute); } return result; } /** * Creates a substitution which maps all variables in this substitution to their * source variable. A variable has a source, if it was created from another one during * a 'fresh' operation. Variables that have no source, will be excluded from this * operation. * * @return A new substitution. */ public Substitution toSource() { final Substitution result = new Substitution( new HashMap<TypeVar, Type>()); for (final Entry<TypeVar, Type> e : this.mappings.entrySet()) { if (e.getKey().source != null) { result.mappings.put(e.getKey().source, e.getValue()); } } return result; } /** * Creates a new substitution by joining this one with the given one. If a mapping for * the same variable exists in both substitutions, the result will contain the * mapping from the given substitution. * * @param s Substitution to join this one with, may be <code>null</code>. * @return A new substitution with mappings from both this and the given substitution. */ public Substitution join(Substitution s) { final Substitution result = new Substitution( new HashMap<TypeVar, Type>()); result.mappings.putAll(this.mappings); if (s != null) { result.mappings.putAll(s.mappings); } return result; } /** * Gets the substitute type for the given type variable. If this set contains no * substitution for the passed variable, the variable itself is returned. * * @param v The variable to find the substitute for. * @return The substitute type expression for the given variable or the variable * itself if there is no such substitute. */ protected Type getSubstitute(TypeVar v) { final Type t = this.mappings.get(v); return t == null ? v : t; } /** * Gets a read-only map view of the substitution mappings. * * @return Map of substitutions. */ public Map<TypeVar, Type> map() { return Collections.unmodifiableMap(this.mappings); } }