]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ELet.java
7b7338a78e2f07efe17b4731a80b709c7635aa35
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / expressions / ELet.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.BoundVar;
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.codegen.writer.RecursiveDefinitionWriter;
16 import org.simantics.scl.compiler.internal.elaboration.decomposed.DecomposedExpression;
17 import org.simantics.scl.compiler.internal.elaboration.utils.StronglyConnectedComponents;
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.kinds.Kinds;
22
23 import gnu.trove.map.hash.TObjectIntHashMap;
24 import gnu.trove.set.hash.THashSet;
25 import gnu.trove.set.hash.TIntHashSet;
26
27 /**
28  * Generated maily from EPreLet
29  */
30 public class ELet extends Expression {
31     public Assignment[] assignments;
32     public Expression in;
33     
34     public ELet(long loc, Assignment[] assignments, Expression in) {
35         super(loc);
36         this.assignments = assignments;
37         this.in = in;
38     }
39     
40     @Override
41     public void collectVars(TObjectIntHashMap<Variable> allVars,
42             TIntHashSet vars) {
43         for(Assignment assign : assignments)
44             assign.value.collectVars(allVars, vars);
45         in.collectVars(allVars, vars);
46     }
47     
48     @Override
49     protected void updateType() throws MatchException {
50         setType(in.getType());
51     }
52    
53     /**
54      * Splits let 
55      */
56     @Override
57     public Expression simplify(SimplificationContext context) {
58         
59         // Simplify assignments
60         for(Assignment assignment : assignments) {
61             assignment.value = assignment.value.simplify(context);
62         }
63         
64         // Find strongly connected components
65         final TObjectIntHashMap<Variable> allVars = new TObjectIntHashMap<Variable>(
66                 2*assignments.length, 0.5f, -1);
67
68         for(int i=0;i<assignments.length;++i)
69             for(Variable var : assignments[i].pattern.getFreeVariables())
70                 allVars.put(var, i);
71         final boolean isRecursive[] = new boolean[assignments.length];
72         final ArrayList<int[]> components = new ArrayList<int[]>(Math.max(10, assignments.length)); 
73         new StronglyConnectedComponents(assignments.length) {
74             @Override
75             protected int[] findDependencies(int u) {
76                 TIntHashSet vars = new TIntHashSet();
77                 assignments[u].value.collectVars(allVars, vars);
78                 if(vars.contains(u))
79                     isRecursive[u] = true;
80                 return vars.toArray();
81             }
82
83             @Override
84             protected void reportComponent(int[] component) {
85                 components.add(component);
86             }
87
88         }.findComponents();
89
90         // Simplify in
91         Expression result = in.simplify(context);
92         
93         // Handle each component
94         for(int j=components.size()-1;j>=0;--j) {
95             int[] component = components.get(j);
96             boolean recursive = component.length > 1 || isRecursive[component[0]];
97             if(recursive) {
98                 Assignment[] cAssignments = new Assignment[component.length];
99                 for(int i=0;i<component.length;++i)
100                     cAssignments[i] = assignments[component[i]];
101                 result = new ELet(location, cAssignments, result);
102             }
103             else {
104                 Assignment assignment = assignments[component[0]];
105                 Expression pattern = assignment.pattern;
106                 
107                 if(pattern instanceof EVariable) {
108                     EVariable pvar = (EVariable)pattern;
109                     result = new ESimpleLet(location, pvar.variable, assignment.value, result);
110                 }
111                 else {
112                     result = new EMatch(location, new Expression[] {assignment.value},
113                                     new Case(new Expression[] {pattern}, result));
114                 }
115             }
116         }
117         
118         return result;
119     }
120
121     @Override
122     public void collectFreeVariables(THashSet<Variable> vars) {
123         in.collectFreeVariables(vars);
124         for(Assignment assign : assignments)
125             assign.value.collectFreeVariables(vars);
126         for(Assignment assign : assignments) 
127             assign.pattern.removeFreeVariables(vars);
128     }
129
130     @Override
131     public Expression resolve(TranslationContext context) {
132         throw new InternalCompilerError("ELet should be already resolved.");
133     }
134     
135     @Override
136     public Expression replace(ReplaceContext context) {
137         Assignment[] newAssignments = new Assignment[assignments.length];
138         for(int i=0;i<assignments.length;++i)
139             newAssignments[i] = assignments[i].replace(context);            
140         Expression newIn = in.replace(context);
141         return new ELet(getLocation(), newAssignments, newIn);
142     }
143     
144     @Override
145     public IVal toVal(CompilationContext context, CodeWriter w) {
146         // Create bound variables
147         BoundVar[] vars = new BoundVar[assignments.length];
148         for(int i=0;i<assignments.length;++i) {
149             Expression pattern = assignments[i].pattern;
150             if(!(pattern instanceof EVariable))
151                 throw new InternalCompilerError("Cannot handle pattern targets in recursive assignments.");
152             vars[i] = new BoundVar(pattern.getType());
153             ((EVariable)pattern).getVariable().setVal(vars[i]);
154         }
155         
156         // Create values
157         RecursiveDefinitionWriter rdw = w.createRecursiveDefinition();
158         long range = Locations.NO_LOCATION;
159         for(Assignment assign2 : assignments) {
160             range = Locations.combine(range, assign2.pattern.location);
161             range = Locations.combine(range, assign2.value.location);
162         }
163         rdw.setLocation(range);
164         for(int i=0;i<assignments.length;++i) {
165             DecomposedExpression decomposed = 
166                     DecomposedExpression.decompose(context.errorLog, assignments[i].value);
167             CodeWriter newW = rdw.createFunction(vars[i], 
168                     decomposed.typeParameters,
169                     decomposed.effect,
170                     decomposed.returnType, 
171                     decomposed.parameterTypes);
172             IVal[] parameters = newW.getParameters();
173             for(int j=0;j<parameters.length;++j)
174                 decomposed.parameters[j].setVal(parameters[j]);
175             newW.return_(decomposed.body.toVal(context, newW));
176         }
177         return in.toVal(context, w);
178     }
179         
180     private void checkAssignments(TypingContext context) {
181         for(Assignment assign : assignments)
182             assign.pattern = assign.pattern.checkTypeAsPattern(context, Types.metaVar(Kinds.STAR));
183         for(Assignment assign : assignments)
184             assign.value = assign.value.checkType(context, assign.pattern.getType());
185     }
186     
187     @Override
188     public Expression inferType(TypingContext context) {
189         checkAssignments(context);
190         in = in.inferType(context);
191         return this;
192     }
193     
194     @Override
195     public Expression checkBasicType(TypingContext context, Type requiredType) {
196         checkAssignments(context);
197         in = in.checkType(context, requiredType);
198         return this;
199     }
200     
201     @Override
202     public Expression checkIgnoredType(TypingContext context) {
203         checkAssignments(context);
204         in = in.checkIgnoredType(context);
205         return this;
206     }
207
208     @Override
209     public void collectEffects(THashSet<Type> effects) {
210         for(Assignment assignment : assignments) {
211             assignment.pattern.collectEffects(effects);
212             assignment.value.collectEffects(effects);
213         }
214         in.collectEffects(effects);
215     }
216     
217     @Override
218     public void setLocationDeep(long loc) {
219         if(location == Locations.NO_LOCATION) {
220             location = loc;
221             for(Assignment assignment : assignments)
222                 assignment.setLocationDeep(loc);
223             in.setLocationDeep(loc);
224         }
225     }
226     
227     @Override
228     public void accept(ExpressionVisitor visitor) {
229         visitor.visit(this);
230     }
231     
232     @Override
233     public Expression accept(ExpressionTransformer transformer) {
234         return transformer.transform(this);
235     }
236     
237     @Override
238     public int getSyntacticFunctionArity() {
239         return in.getSyntacticFunctionArity();
240     }
241
242 }