package org.simantics.scl.compiler.types; import java.util.ArrayList; import java.util.List; import org.simantics.scl.compiler.environment.Environment; import org.simantics.scl.compiler.internal.types.HashCodeUtils; import org.simantics.scl.compiler.internal.types.TypeHashCodeContext; import org.simantics.scl.compiler.internal.types.ast.TApplyAst; import org.simantics.scl.compiler.internal.types.ast.TListAst; import org.simantics.scl.compiler.internal.types.ast.TTupleAst; import org.simantics.scl.compiler.internal.types.ast.TypeAst; import org.simantics.scl.compiler.types.exceptions.KindUnificationException; import org.simantics.scl.compiler.types.kinds.Kind; import org.simantics.scl.compiler.types.kinds.Kinds; import org.simantics.scl.compiler.types.util.Polarity; import org.simantics.scl.compiler.types.util.TMultiApply; import org.simantics.scl.compiler.types.util.TypeUnparsingContext; import gnu.trove.map.hash.THashMap; import gnu.trove.set.hash.THashSet; /** * Type application. * @author Hannu Niemistö */ public class TApply extends Type { public Type function; public Type parameter; public TApply(Type function, Type parameter) { if(NULL_CHECKS) { if(function == null) throw new NullPointerException(); if(parameter == null) throw new NullPointerException(); } this.function = function; this.parameter = parameter; } private TApply create(Type function, Type parameter) { if(function == this.function && parameter == this.parameter) return this; else return new TApply(function, parameter); } @Override public TApply replace(TVar var, Type replacement) { return create( function.replace(var, replacement), parameter.replace(var, replacement)); } @Override public TypeAst toTypeAst(TypeUnparsingContext context) { TMultiApply multiApply = Types.toMultiApply(this); Type function = multiApply.function; List parameters = multiApply.parameters; TypeAst ast = null; int parameterPos = 0; if(function instanceof TCon) { /*if(function == Types.ARROW && parameters.size() >= 2) { ast = new TFunctionAst( parameters.get(0).toTypeAst(context), parameters.get(1).toTypeAst(context)); parameterPos = 2; } else*/ if(function == Types.LIST && parameters.size() >= 1) { ast = new TListAst( parameters.get(0).toTypeAst(context)); parameterPos = 1; } else { TCon con = (TCon)function; if(con.module == Types.BUILTIN && con.name.charAt(0)=='(') { int tupleLength = con.name.length()-2; if(tupleLength>0) ++tupleLength; if(parameters.size() >= tupleLength) { TypeAst[] components = new TypeAst[tupleLength]; for(int i=0;i vars) { function.collectFreeVars(vars); parameter.collectFreeVars(vars); } @Override public void collectMetaVars(ArrayList vars) { function.collectMetaVars(vars); parameter.collectMetaVars(vars); } @Override public void collectMetaVars(THashSet vars) { function.collectMetaVars(vars); parameter.collectMetaVars(vars); } @Override public void collectEffectMetaVars(ArrayList vars) { function.collectEffectMetaVars(vars); parameter.collectEffectMetaVars(vars); } @Override public boolean contains(TMetaVar other) { return function.contains(other) || parameter.contains(other); } @Override public Type convertMetaVarsToVars() { Type newFunction = function.convertMetaVarsToVars(); Type newParameter = parameter.convertMetaVarsToVars(); if(newFunction == function && newParameter == parameter) return this; else return new TApply(newFunction, newParameter); } @Override public boolean isGround() { return function.isGround() && parameter.isGround(); } public void checkKind(Environment context, Kind requiredKind) throws KindUnificationException { Kind functionKind = function.inferKind(context); Kind parameterKind = parameter.inferKind(context); Kinds.unify(functionKind, Kinds.arrow(parameterKind, requiredKind)); } @Override public Kind getKind(Environment context) { Kind functionKind = function.getKind(context); return Kinds.rangeOfArrow(functionKind); } @Override public boolean containsMetaVars() { return function.containsMetaVars() || parameter.containsMetaVars(); } @Override public void toName(TypeUnparsingContext context, StringBuilder b) { function.toName(context, b); b.append('_'); parameter.toName(context, b); } @Override public int getClassId() { return APPLY_ID; } @Override public void addPolarity(Polarity polarity) { function.addPolarity(Polarity.BIPOLAR); parameter.addPolarity(Polarity.BIPOLAR); } @Override public Type head() { return function.head(); } @Override public Type copySkeleton(THashMap metaVarMap) { Type newFunction = function.copySkeleton(metaVarMap); Type newParameter = parameter.copySkeleton(metaVarMap); if(newFunction == function && newParameter == parameter) return this; else return new TApply(newFunction, newParameter); } @Override public int hashCode(int hash) { hash = HashCodeUtils.updateWithPreprocessedValue(hash, APPLY_HASH); hash = function.hashCode(hash); hash = parameter.hashCode(hash); return hash; } @Override public int hashCode(int hash, TVar[] boundVars) { hash = HashCodeUtils.updateWithPreprocessedValue(hash, APPLY_HASH); hash = function.hashCode(hash, boundVars); hash = parameter.hashCode(hash, boundVars); return hash; } @Override public int skeletonHashCode(int hash) { hash = HashCodeUtils.updateWithPreprocessedValue(hash, APPLY_HASH); hash = function.skeletonHashCode(hash); hash = parameter.skeletonHashCode(hash); return hash; } @Override public int skeletonHashCode(int hash, TVar[] boundVars) { hash = HashCodeUtils.updateWithPreprocessedValue(hash, APPLY_HASH); hash = function.skeletonHashCode(hash, boundVars); hash = parameter.skeletonHashCode(hash, boundVars); return hash; } public Type getCanonicalFunction() { if(function instanceof TMetaVar) function = function.canonical(); return function; } public Type getCanonicalParameter() { if(parameter instanceof TMetaVar) parameter = parameter.canonical(); return parameter; } @Override public boolean equalsCanonical(Type other) { if(this == other) return true; if(!other.getClass().equals(TApply.class)) return false; TApply apply = (TApply)other; return getCanonicalFunction().equalsCanonical(apply.getCanonicalFunction()) && getCanonicalParameter().equalsCanonical(apply.getCanonicalParameter()); } @Override public Type[] skeletonCanonicalChildren() { return new Type[] {Skeletons.canonicalSkeleton(function), Skeletons.canonicalSkeleton(parameter)}; } }