9b3ee8df77bcdb7812f8ef3f8472cbe83bf34bec
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / expressions / ESimpleLambda.java
1 package org.simantics.scl.compiler.elaboration.expressions;
2
3 import java.util.ArrayList;
4
5 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
6 import org.simantics.scl.compiler.compilation.CompilationContext;
7 import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext;
8 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
9 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
10 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
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.interpreted.IExpression;
15 import org.simantics.scl.compiler.internal.interpreted.ILambda;
16 import org.simantics.scl.compiler.top.ExpressionInterpretationContext;
17 import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
18 import org.simantics.scl.compiler.types.Type;
19 import org.simantics.scl.compiler.types.Types;
20 import org.simantics.scl.compiler.types.exceptions.MatchException;
21 import org.simantics.scl.compiler.types.exceptions.UnificationException;
22 import org.simantics.scl.compiler.types.kinds.Kinds;
23 import org.simantics.scl.compiler.types.util.MultiFunction;
24
25 import gnu.trove.map.hash.TObjectIntHashMap;
26 import gnu.trove.set.hash.THashSet;
27 import gnu.trove.set.hash.TIntHashSet;
28
29 public class ESimpleLambda extends Expression {
30     public Variable parameter;
31     public Expression value;
32     public Type effect = Types.NO_EFFECTS;
33     
34     public ESimpleLambda(Variable parameter, Expression value) {
35         this.parameter = parameter;
36         this.value = value;
37     }
38     
39     public ESimpleLambda(Type effect, Variable parameter, Expression value) {
40         this.parameter = parameter;
41         this.value = value;
42         this.effect = effect;
43     }
44
45     public ESimpleLambda(long loc, Variable parameter, Expression value) {
46         super(loc);
47         this.parameter = parameter;
48         this.value = value;
49     }
50     
51     public ESimpleLambda(long loc, Variable parameter, Type effect, Expression value) {
52         super(loc);
53         this.parameter = parameter;
54         this.value = value;
55         this.effect = effect;
56     }
57
58     @Override
59     public void collectVars(TObjectIntHashMap<Variable> allVars,
60             TIntHashSet vars) {
61         value.collectVars(allVars, vars);
62     }
63
64     public Expression decomposeMatching() {
65         value = value.decomposeMatching();
66         return this;
67     }
68
69         @Override
70         protected void updateType() throws MatchException {
71             setType(Types.functionE(Types.canonical(parameter.type),
72                     effect, value.getType()));
73         }
74         
75         @Override
76         public IVal toVal(CompilationContext context, CodeWriter w) {
77             return lambdaToVal(context, w);
78     }
79
80     @Override
81     public void collectFreeVariables(THashSet<Variable> vars) {
82         value.collectFreeVariables(vars);
83         vars.remove(parameter);
84     }
85
86     @Override
87     public Expression simplify(SimplificationContext context) {
88         value = value.simplify(context);
89         return this;
90     }
91
92     @Override
93     public Expression resolve(TranslationContext context) {
94         value = value.resolve(context);
95         return this;
96     }
97
98     @Override
99     public Expression replace(ReplaceContext context) {
100         Variable newParameter = parameter.copy();
101         context.varMap.put(parameter, new EVariable(newParameter));
102         ESimpleLambda result = new ESimpleLambda(getLocation(),
103                 newParameter, 
104                 effect.replace(context.tvarMap),
105                 value.replace(context));
106         // not absolutely needed, but maybe good for performance
107         context.varMap.remove(parameter); 
108         return result;
109     }
110         
111     public Type getLocalEffect() {
112         if(SCLCompilerConfiguration.DEBUG)
113             if(effect == null)
114                 throw new InternalCompilerError();
115         return effect;
116     }
117     
118     public void setEffect(Type effect) {
119         if(effect == null)
120             throw new InternalCompilerError();
121         this.effect = effect;
122     }
123     
124     @Override
125     public IExpression toIExpression(ExpressionInterpretationContext context) {
126         // Find parameters of the whole function definition
127         ArrayList<Variable> parameters = new ArrayList<Variable>(2);
128         parameters.add(parameter);
129         Expression cur = value;
130         while(true) {
131             if(cur instanceof ESimpleLambda) {
132                 ESimpleLambda lambda = (ESimpleLambda)cur;
133                 parameters.add(lambda.parameter);
134                 cur = lambda.value;
135             }
136             else if(cur instanceof ELambdaType) {
137                 cur = ((ELambdaType)cur).value;
138             }
139             else
140                 break;
141             
142         }
143         
144         // Free variables;
145         ExpressionInterpretationContext innerContext =  context.createNewContext();
146         THashSet<Variable> freeVariables = cur.getFreeVariables();
147         for(Variable parameter : parameters)
148             freeVariables.remove(parameter);
149         int i=0;
150         int[] inheritedVariableIds = new int[freeVariables.size()];
151         for(Variable var : freeVariables) {
152             innerContext.push(var);
153             inheritedVariableIds[i++] = context.getVariableId(var);
154         }
155         
156         // Parameters
157         for(Variable parameter : parameters)
158             innerContext.push(parameter);
159         
160         // Construct lambda
161         IExpression body = cur.toIExpression(innerContext); 
162         return new ILambda(inheritedVariableIds,
163                 parameters.size(),
164                 innerContext.getMaxVariableId(),
165                 body);
166     }
167     
168     public Expression checkBasicType(TypingContext context, Type requiredType) {
169         MultiFunction mfun;
170         try {
171             mfun = Types.unifyFunction(requiredType, 1);
172         } catch (UnificationException e) {
173             context.getErrorLog().log(location, "Required type is <" + requiredType + "> which is incompatible with lambda.");
174             setType(Types.metaVar(Kinds.STAR));
175             return this;
176         }
177         
178         context.pushEffectUpperBound(location, mfun.effect);
179         parameter.setType(mfun.parameterTypes[0]);
180         value = value.checkType(context, mfun.returnType);
181         effect = context.popEffectUpperBound();
182         return this;
183     }
184     
185     @Override
186     public Expression inferType(TypingContext context) {
187         effect = Types.metaVar(Kinds.EFFECT);
188         context.pushEffectUpperBound(location, effect);
189         if(parameter.type == null)
190             parameter.setType(Types.metaVar(Kinds.STAR));
191         value = value.checkType(context, Types.metaVar(Kinds.STAR));
192         context.popEffectUpperBound();
193         return this;
194     }
195
196     @Override
197     public boolean isEffectful() {
198         return false;
199     }
200     
201     @Override
202     public void setLocationDeep(long loc) {
203         if(location == Locations.NO_LOCATION) {
204             location = loc;
205             value.setLocationDeep(loc);
206         }
207     }
208     
209     @Override
210     public void accept(ExpressionVisitor visitor) {
211         visitor.visit(this);
212     }
213     
214     public Expression getValue() {
215         return value;
216     }
217     
218     public Variable getParameter() {
219         return parameter;
220     }
221     
222     @Override
223     public Expression accept(ExpressionTransformer transformer) {
224         return transformer.transform(this);
225     }
226     
227     @Override
228     public int getSyntacticFunctionArity() {
229         return 1 + value.getSyntacticFunctionArity();
230     }
231
232 }