1 package org.simantics.scl.compiler.elaboration.expressions;
3 import java.util.ArrayList;
5 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
6 import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext;
7 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
8 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
9 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
10 import org.simantics.scl.compiler.environment.Environment;
11 import org.simantics.scl.compiler.errors.Locations;
12 import org.simantics.scl.compiler.internal.codegen.references.IVal;
13 import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;
14 import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator;
15 import org.simantics.scl.compiler.internal.interpreted.IExpression;
16 import org.simantics.scl.compiler.internal.interpreted.ILambda;
17 import org.simantics.scl.compiler.top.ExpressionInterpretationContext;
18 import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
19 import org.simantics.scl.compiler.types.Type;
20 import org.simantics.scl.compiler.types.Types;
21 import org.simantics.scl.compiler.types.exceptions.MatchException;
22 import org.simantics.scl.compiler.types.exceptions.UnificationException;
23 import org.simantics.scl.compiler.types.kinds.Kinds;
24 import org.simantics.scl.compiler.types.util.MultiFunction;
26 import gnu.trove.map.hash.TObjectIntHashMap;
27 import gnu.trove.set.hash.THashSet;
28 import gnu.trove.set.hash.TIntHashSet;
30 public class ESimpleLambda extends Expression {
31 public Variable parameter;
32 public Expression value;
33 public Type effect = Types.NO_EFFECTS;
35 public ESimpleLambda(Variable parameter, Expression value) {
36 this.parameter = parameter;
40 public ESimpleLambda(Type effect, Variable parameter, Expression value) {
41 this.parameter = parameter;
46 public ESimpleLambda(long loc, Variable parameter, Expression value) {
48 this.parameter = parameter;
52 public ESimpleLambda(long loc, Variable parameter, Type effect, Expression value) {
54 this.parameter = parameter;
59 public void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs) {
60 value.collectRefs(allRefs, refs);
64 public void collectVars(TObjectIntHashMap<Variable> allVars,
66 value.collectVars(allVars, vars);
69 public Expression decomposeMatching() {
70 value = value.decomposeMatching();
75 protected void updateType() throws MatchException {
76 setType(Types.functionE(Types.canonical(parameter.type),
77 effect, value.getType()));
81 public IVal toVal(Environment env, CodeWriter w) {
82 return lambdaToVal(env, w);
86 public void collectFreeVariables(THashSet<Variable> vars) {
87 value.collectFreeVariables(vars);
88 vars.remove(parameter);
92 public Expression simplify(SimplificationContext context) {
93 value = value.simplify(context);
98 public Expression resolve(TranslationContext context) {
99 value = value.resolve(context);
104 public Expression replace(ReplaceContext context) {
105 Variable newParameter = parameter.copy();
106 context.varMap.put(parameter, new EVariable(newParameter));
107 ESimpleLambda result = new ESimpleLambda(getLocation(),
109 effect.replace(context.tvarMap),
110 value.replace(context));
111 // not absolutely needed, but maybe good for performance
112 context.varMap.remove(parameter);
116 public Type getLocalEffect() {
117 if(SCLCompilerConfiguration.DEBUG)
119 throw new InternalCompilerError();
123 public void setEffect(Type effect) {
125 throw new InternalCompilerError();
126 this.effect = effect;
130 public IExpression toIExpression(ExpressionInterpretationContext context) {
131 // Find parameters of the whole function definition
132 ArrayList<Variable> parameters = new ArrayList<Variable>(2);
133 parameters.add(parameter);
134 Expression cur = value;
136 if(cur instanceof ESimpleLambda) {
137 ESimpleLambda lambda = (ESimpleLambda)cur;
138 parameters.add(lambda.parameter);
141 else if(cur instanceof ELambdaType) {
142 cur = ((ELambdaType)cur).value;
150 ExpressionInterpretationContext innerContext = context.createNewContext();
151 THashSet<Variable> freeVariables = cur.getFreeVariables();
152 for(Variable parameter : parameters)
153 freeVariables.remove(parameter);
155 int[] inheritedVariableIds = new int[freeVariables.size()];
156 for(Variable var : freeVariables) {
157 innerContext.push(var);
158 inheritedVariableIds[i++] = context.getVariableId(var);
162 for(Variable parameter : parameters)
163 innerContext.push(parameter);
166 IExpression body = cur.toIExpression(innerContext);
167 return new ILambda(inheritedVariableIds,
169 innerContext.getMaxVariableId(),
173 public Expression checkBasicType(TypingContext context, Type requiredType) {
176 mfun = Types.unifyFunction(requiredType, 1);
177 } catch (UnificationException e) {
178 context.getErrorLog().log(location, "Required type is <" + requiredType + "> which is incompatible with lambda.");
179 setType(Types.metaVar(Kinds.STAR));
183 effect = mfun.effect;
184 context.pushEffectUpperBound(location, mfun.effect);
185 parameter.setType(mfun.parameterTypes[0]);
186 value = value.checkType(context, mfun.returnType);
187 context.popEffectUpperBound();
192 public Expression inferType(TypingContext context) {
193 effect = Types.metaVar(Kinds.EFFECT);
194 context.pushEffectUpperBound(location, effect);
195 if(parameter.type == null)
196 parameter.setType(Types.metaVar(Kinds.STAR));
197 value = value.checkType(context, Types.metaVar(Kinds.STAR));
198 context.popEffectUpperBound();
203 public Expression decorate(ExpressionDecorator decorator) {
204 if(decorator.decorateSubstructure(this))
205 value = value.decorate(decorator);
206 return decorator.decorate(this);
210 public boolean isEffectful() {
215 public void collectEffects(THashSet<Type> effects) {
219 public void setLocationDeep(long loc) {
220 if(location == Locations.NO_LOCATION) {
222 value.setLocationDeep(loc);
227 public void accept(ExpressionVisitor visitor) {
231 public Expression getValue() {
235 public Variable getParameter() {
240 public void forVariables(VariableProcedure procedure) {
241 value.forVariables(procedure);
245 public Expression accept(ExpressionTransformer transformer) {
246 return transformer.transform(this);
250 public int getSyntacticFunctionArity() {
251 return 1 + value.getSyntacticFunctionArity();