1 package org.simantics.scl.compiler.internal.elaboration.transformations;
3 import java.util.ArrayList;
5 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
6 import org.simantics.scl.compiler.common.names.Names;
7 import org.simantics.scl.compiler.constants.Constant;
8 import org.simantics.scl.compiler.constants.StringConstant;
9 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
10 import org.simantics.scl.compiler.elaboration.expressions.EApply;
11 import org.simantics.scl.compiler.elaboration.expressions.EConstant;
12 import org.simantics.scl.compiler.elaboration.expressions.ELambda;
13 import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
14 import org.simantics.scl.compiler.elaboration.expressions.ESimpleLet;
15 import org.simantics.scl.compiler.elaboration.expressions.EVariable;
16 import org.simantics.scl.compiler.elaboration.expressions.Expression;
17 import org.simantics.scl.compiler.elaboration.expressions.Expressions;
18 import org.simantics.scl.compiler.elaboration.expressions.Variable;
19 import org.simantics.scl.compiler.elaboration.expressions.VariableProcedure;
20 import org.simantics.scl.compiler.elaboration.expressions.block.LetStatement;
21 import org.simantics.scl.compiler.elaboration.expressions.block.Statement;
22 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
23 import org.simantics.scl.compiler.errors.Locations;
24 import org.simantics.scl.compiler.internal.codegen.references.IVal;
25 import org.simantics.scl.compiler.internal.types.HashCodeUtils;
26 import org.simantics.scl.compiler.types.TCon;
27 import org.simantics.scl.compiler.types.Type;
28 import org.simantics.scl.compiler.types.Types;
29 import org.simantics.scl.compiler.types.exceptions.MatchException;
30 import org.simantics.scl.compiler.types.util.MultiApply;
31 import org.simantics.scl.compiler.types.util.MultiFunction;
33 import gnu.trove.map.hash.THashMap;
34 import gnu.trove.set.hash.THashSet;
36 public class UnifiableFactory {
37 private final TypingContext context;
39 * The factory generates here the statements initializing the variables needed in unification.
41 private final ArrayList<Statement> mappingStatements;
42 private THashMap<Type, Variable> defaultGenerators =
43 new THashMap<Type, Variable>();
45 public UnifiableFactory(TypingContext context, ArrayList<Statement> phase2Statements) {
46 this.context = context;
47 this.mappingStatements = phase2Statements;
51 * Converts an expression of type {@code T} to an expression of type {@code Unifiable T}
52 * @param variableSet The unifiable variables
53 * @param uniVariableMap A map from ordinary variables to unifiables
54 * @param expression The expression that is converted
57 private Expression toUnifiable(
58 THashSet<Variable> variableSet,
59 THashMap<Variable, Variable> uniVariableMap,
60 Expression expression) {
61 UnifiableRep rep = toUnifiableRep(variableSet, uniVariableMap, expression);
62 return rep.toExpression();
65 static interface UnifiableRep {
66 Expression toExpression();
69 class ConstantRep implements UnifiableRep {
70 final Expression constant;
71 public ConstantRep(Expression constant) {
72 this.constant = constant;
75 public Expression toExpression() {
76 return Expressions.apply(context.getCompilationContext(), Types.NO_EFFECTS, Names.Unifiable_uId,
77 constant.getType(), constant);
81 class PendingRep implements UnifiableRep {
82 final THashSet<Variable> dependences;
83 final THashMap<Variable, Variable> uniVariableMap;
84 final Expression value;
85 public PendingRep(THashSet<Variable> dependences, THashMap<Variable, Variable> uniVariableMap,
87 this.dependences = dependences;
88 this.uniVariableMap = uniVariableMap;
92 public Expression toExpression() {
93 Expression expression = value;
94 for(Variable variable : dependences)
95 expression = new ESimpleLet(
97 extract(variable.getType(), Expressions.var(uniVariableMap.get(variable))),
99 return Expressions.apply(context.getCompilationContext(), Types.NO_EFFECTS, Names.Unifiable_uPending,
100 value.getType(), Expressions.computation(Types.PROC, expression));
104 static class UniRep implements UnifiableRep {
105 final Expression uni;
106 public UniRep(Expression uni) {
110 public Expression toExpression() {
116 * Returns null, if does not contain variables from variableSet
118 private UnifiableRep toUnifiableRep(
119 final THashSet<Variable> variableSet,
120 final THashMap<Variable, Variable> uniVariableMap,
121 Expression expression) {
122 if(expression instanceof EVariable) {
123 Variable variable = ((EVariable)expression).getVariable();
124 if(!variableSet.contains(variable))
125 return new ConstantRep(expression);
127 Variable uniVariable = uniVariableMap.get(variable);
128 if(uniVariable != null)
129 return new UniRep(new EVariable(uniVariable));
131 return new UniRep(Expressions.apply(context.getCompilationContext(), Types.PROC, Names.Unifiable_uVar, variable.getType(), Expressions.punit()));
134 if(expression instanceof EApply) {
135 EApply apply = (EApply)expression;
137 if(!(apply.getFunction() instanceof EConstant))
139 EConstant function = (EConstant)apply.getFunction();
141 IVal val = function.getValue().getValue();
142 if(!(val instanceof Constant))
144 Constant constant = (Constant)val;
146 int constructorTag = constant.constructorTag();
147 if(constructorTag < 0)
150 int arity = constant.getArity();
151 Expression[] parameters = apply.getParameters();
152 if(arity != parameters.length)
155 boolean hasUnifiableParameter = false;
156 boolean hasPendingParameter = false;
157 UnifiableRep[] uniParameters = new UnifiableRep[arity];
158 for(int i=0;i<arity;++i) {
159 UnifiableRep uRep = toUnifiableRep(variableSet, uniVariableMap, parameters[i]);
160 uniParameters[i] = uRep;
161 if(uRep instanceof UniRep)
162 hasUnifiableParameter = true;
163 else if(uRep instanceof PendingRep)
164 hasPendingParameter = true;
167 if(hasUnifiableParameter) {
168 Expression[] tupleParameters = new Expression[arity];
169 for(int i=0;i<arity;++i)
170 tupleParameters[i] = uniParameters[i].toExpression();
171 Expression tuple = Expressions.tuple(tupleParameters);
172 return new UniRep(Expressions.apply(context.getCompilationContext(), Types.NO_EFFECTS, Names.Unifiable_uCons,
173 expression.getType(), tuple.getType(),
174 getTag(function), tuple));
176 else if(hasPendingParameter) {
177 THashSet<Variable> dependences = new THashSet<Variable>();
178 for(UnifiableRep uRep : uniParameters)
179 if(uRep instanceof PendingRep)
180 dependences.addAll(((PendingRep)uRep).dependences);
181 return new PendingRep(dependences, uniVariableMap, expression);
184 return new ConstantRep(expression);
188 final THashSet<Variable> dependences = new THashSet<Variable>();
189 expression.forVariables(new VariableProcedure() {
192 public void execute(long location, Variable variable) {
193 if(variableSet.contains(variable))
194 dependences.add(variable);
197 if(dependences.isEmpty())
198 return new ConstantRep(expression);
200 return new PendingRep(dependences, uniVariableMap, expression);
203 private static class Constructor {
204 final SCLValue function;
205 final Type[] typeParameters;
206 private int hashCode;
208 public Constructor(SCLValue function, Type[] typeParameters) {
209 this.function = function;
210 this.typeParameters = typeParameters;
214 public boolean equals(Object obj) {
217 if(obj == null || obj.getClass() != Constructor.class)
219 Constructor other = (Constructor)obj;
220 if(function != other.function)
222 return Types.equals(typeParameters, other.typeParameters);
226 public int hashCode() {
228 int hash = HashCodeUtils.SEED;
229 hash = HashCodeUtils.update(hash, function.hashCode());
230 for(Type typeParameter : typeParameters)
231 hash = typeParameter.hashCode(hash);
238 private THashMap<Constructor, Variable> constructorTags =
239 new THashMap<Constructor, Variable>();
241 private Expression getTag(EConstant constructorExpr) {
242 Constructor key = new Constructor(constructorExpr.getValue(),
243 constructorExpr.getTypeParameters());
244 Variable tag = constructorTags.get(key);
246 SCLValue sclValue = constructorExpr.getValue();
247 Constant constant = (Constant)sclValue.getValue();
248 int arity = constant.getArity();
249 int constructorTag = constant.constructorTag();
252 mfun = Types.matchFunction(constructorExpr.getType(), arity);
253 } catch (MatchException e) {
254 throw new InternalCompilerError(e);
257 Type[] uniParameterTypes = new Type[arity];
258 for(int i=0;i<arity;++i)
259 uniParameterTypes[i] = Types.apply(Names.Unifiable_Unifiable, mfun.parameterTypes[i]);
260 Type tupleType = Types.tuple(uniParameterTypes);
263 Expression destructor;
264 if(sclValue.getName().module.equals("Builtin") && sclValue.getName().name.charAt(0)=='(') {
265 // Tuple constructor is a special case, where we can just cast the value
266 destructor = Expressions.constant(context.getCompilationContext(), Names.JavaBuiltin_unsafeCoerce, mfun.returnType, tupleType);
269 Variable[] parameters = new Variable[arity];
270 for(int i=0;i<arity;++i)
271 parameters[i] = new Variable("p" + i, mfun.parameterTypes[i]);
272 Expression pattern = new EApply(constructorExpr.copy(context), Expressions.vars(parameters));
273 Expression[] tupleParameters = new Expression[arity];
274 for(int i=0;i<arity;++i)
275 tupleParameters[i] = Expressions.apply(context.getCompilationContext(), Types.NO_EFFECTS, Names.Unifiable_uId,
276 parameters[i].getType(), Expressions.var(parameters[i]));
277 Expression value = Expressions.tuple(tupleParameters);
278 destructor = new ELambda(Locations.NO_LOCATION, pattern, value);
282 Expression constructor;
284 Variable[] parameters = new Variable[arity];
285 for(int i=0;i<arity;++i)
286 parameters[i] = new Variable("p" + i, uniParameterTypes[i]);
287 Expression pattern = Expressions.tuple(Expressions.vars(parameters));
288 Expression[] constructorParameters = new Expression[arity];
289 for(int i=0;i<arity;++i)
290 constructorParameters[i] = extract(mfun.parameterTypes[i], Expressions.var(parameters[i]));
291 Expression value = new EApply(constructorExpr.copy(context), constructorParameters);
292 constructor = new ELambda(Locations.NO_LOCATION, pattern, value);
295 tag = new Variable("tag", Types.apply(Names.Unifiable_UTag, mfun.returnType, tupleType));
296 mappingStatements.add(new LetStatement(new EVariable(tag),
297 Expressions.apply(context.getCompilationContext(), Types.NO_EFFECTS, Names.Unifiable_uTag, tupleType, mfun.returnType,
298 Expressions.integer(constructorTag), constructor, destructor)));
299 constructorTags.put(key, tag);
301 return new EVariable(tag);
304 private Expression extract(Type type, Expression uni) {
305 return Expressions.apply(context.getCompilationContext(), Types.PROC, Names.Unifiable_extractWithDefault,
306 type, getDefaultGenerator(type), uni);
310 * Returns for the given type {@code T} a generator
311 * of type {@code <Proc> T} that generates the values of the type.
313 private Expression getDefaultGenerator(Type type) {
314 Variable generator = defaultGenerators.get(type);
315 if(generator == null) {
316 generator = new Variable("defGen", Types.functionE(Types.PUNIT, Types.PROC, type));
317 mappingStatements.add(new LetStatement(new EVariable(generator),
318 Expressions.computation(Types.PROC, createGenerationExpression(type))
320 defaultGenerators.put(type, generator);
322 return new EVariable(generator);
325 private Expression createGenerationExpression(Type type) {
326 MultiApply apply = Types.matchApply(type);
327 //System.out.println("createGenerationExpression(" + type.toString(tuc) + ")");
328 if(apply.constructor instanceof TCon) {
329 if(apply.constructor.equals(Types.RESOURCE))
330 return Expressions.apply(context.getCompilationContext(), Types.PROC, Names.Simantics_DB_newResource, Expressions.tuple());
332 if(apply.constructor.equals(Types.STRING))
333 return new ELiteral(new StringConstant("")); // FIXME
335 if(apply.constructor.equals(Names.Data_XML_Element))
336 return Expressions.apply(context.getCompilationContext(), Types.PROC, Names.Data_XML_createElement, Expressions.string("NO-NAME"));
338 TCon con = (TCon)apply.constructor;
339 if(con.name.charAt(0) == '(') { // (), (,), (,,),...
340 int arity = con.name.length()-1;
343 if(arity != apply.parameters.length)
344 throw new InternalCompilerError();
345 Expression[] parameters = new Expression[arity];
346 for(int i=0;i<arity;++i)
347 parameters[i] = new EApply(Locations.NO_LOCATION, Types.PROC,
348 getDefaultGenerator(apply.parameters[i]), Expressions.punit());
349 return Expressions.tuple(parameters);
352 return Expressions.apply(context.getCompilationContext(), Types.NO_EFFECTS, Names.Builtin_fail,
353 new ELiteral(new StringConstant("Cannot generated default instance for type " + type + ".")));
356 public Expression generateDefaultValue(Type type) {
357 return Expressions.apply(Types.PROC, getDefaultGenerator(type), Expressions.punit());
360 public Expression getFromUMap(Expression umap, Expression key, Type valueType) {
361 return Expressions.apply(context.getCompilationContext(), Types.PROC,
362 Names.Unifiable_getUMapWithDefault,
365 getDefaultGenerator(valueType),
370 public Expression putToUMapUnifiable(
371 THashSet<Variable> variableSet, THashMap<Variable, Variable> uniVariableMap,
372 Expression umap, Expression key, Expression value) {
373 return Expressions.apply(context.getCompilationContext(), Types.PROC,
374 Names.Unifiable_putUMap,
379 toUnifiable(variableSet, uniVariableMap, value));
382 public Expression putToUMapConstant(Variable umap, Expression key, Expression value) {
383 return Expressions.apply(context.getCompilationContext(), Types.PROC,
384 Names.Unifiable_putUMapC,
385 key.getType(), value.getType(),
386 Expressions.var(umap),