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