]> gerrit.simantics Code Review - simantics/platform.git/blob
573abfbb86055f081f57f49aba4d54db3cb08287
[simantics/platform.git] /
1 package org.simantics.scl.compiler.elaboration.expressions;
2
3 import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext;
4 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
5 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
6 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
7 import org.simantics.scl.compiler.errors.Locations;
8 import org.simantics.scl.compiler.types.Type;
9 import org.simantics.scl.compiler.types.Types;
10 import org.simantics.scl.compiler.types.exceptions.MatchException;
11 import org.simantics.scl.compiler.types.exceptions.UnificationException;
12 import org.simantics.scl.compiler.types.kinds.Kinds;
13 import org.simantics.scl.compiler.types.util.MultiFunction;
14
15 import gnu.trove.map.hash.TObjectIntHashMap;
16 import gnu.trove.set.hash.THashSet;
17 import gnu.trove.set.hash.TIntHashSet;
18
19 public class ELambda extends SimplifiableExpression {
20     public Case[] cases;
21     Type effect = Types.NO_EFFECTS;
22     
23     public ELambda(Case[] cases) {
24         this.cases = cases;
25     }
26     
27     public ELambda(Case case_) {
28         this(new Case[] {case_});
29     }
30
31     public ELambda(long loc, Case ... cases) {
32         super(loc);
33         this.cases = cases;
34     }
35     
36     public ELambda(long loc, Expression pat, Expression exp) {
37         this(loc, new Case(new Expression[] {pat}, exp));
38     }
39
40         public void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs) {
41         for(Case case_ : cases)
42             case_.collectRefs(allRefs, refs);
43     }
44         
45         @Override
46         public void collectVars(TObjectIntHashMap<Variable> allVars,
47                 TIntHashSet vars) {
48             for(Case case_ : cases)
49             case_.collectVars(allVars, vars);
50         }
51
52         public Expression decomposeMatching() {
53             Expression[] patterns = cases[0].patterns;
54         int arity = patterns.length;
55         
56         // Simple cases
57         if(cases.length == 1 && 
58                 !(cases[0].value instanceof GuardedExpressionGroup)) {
59             boolean noMatchingNeeded = true;
60             for(int i=0;i<arity;++i)
61                 if(!(patterns[i] instanceof EVariable)) {
62                     noMatchingNeeded = false;
63                     break;
64                 }
65             if(noMatchingNeeded) {
66                 Expression decomposed = cases[0].value.decomposeMatching();
67                 Type effect = this.effect;
68                 for(int i=arity-1;i>=0;--i) {
69                     Variable var = ((EVariable)patterns[i]).getVariable(); 
70                     decomposed = new ESimpleLambda(getLocation(), var, effect, decomposed);
71                     effect = Types.NO_EFFECTS;
72                 }
73                 return decomposed;
74             }
75         }
76         
77         // Complex case
78         Variable[] vars = new Variable[arity];
79         Expression[] scrutinee = new Expression[arity];
80         for(int i=0;i<arity;++i) {
81             vars[i] = new Variable("temp" + i);
82             Type type = patterns[i].getType();
83             vars[i].setType(type);
84             scrutinee[i] = new EVariable(getLocation(), vars[i]);
85             scrutinee[i].setType(type);
86         }
87         Expression decomposed = new EMatch(getLocation(), scrutinee, cases);
88         Type curEffect = this.effect;
89         for(int i=arity-1;i>=0;--i) {            
90             decomposed = new ESimpleLambda(getLocation(), vars[i], curEffect, decomposed);            
91             curEffect = Types.NO_EFFECTS;                 
92         }
93         return decomposed;
94     }
95         
96         @Override
97         protected void updateType() throws MatchException {
98             setType(Types.functionE(Types.getTypes(cases[0].patterns), effect, cases[0].value.getType()));
99         }
100         
101         @Override
102         public Expression simplify(SimplificationContext context) {
103             return decomposeMatching().simplify(context);
104         }
105
106     @Override
107     public void collectFreeVariables(THashSet<Variable> vars) {
108         for(Case case_ : cases)
109             case_.collectFreeVariables(vars);
110     }
111
112     @Override
113     public Expression resolve(TranslationContext context) {
114         for(Case case_ : cases)
115             case_.resolve(context);
116         return this;
117     }
118     
119     @Override
120     public void setLocationDeep(long loc) {
121         if(location == Locations.NO_LOCATION) {
122             location = loc;
123             for(Case case_ : cases)
124                 case_.setLocationDeep(loc);
125         }
126     }
127     
128     @Override
129     public Expression replace(ReplaceContext context) {
130         Case[] newCases = new Case[cases.length];
131         for(int i=0;i<cases.length;++i)
132             newCases[i] = cases[i].replace(context);
133         return new ELambda(newCases);
134     }
135
136     public Case[] getCases() {
137         return cases;
138     }
139     
140     public Expression checkBasicType(TypingContext context, Type requiredType) {
141         int arity = cases[0].patterns.length;
142         MultiFunction mfun;
143         try {
144             mfun = Types.unifyFunction(requiredType, arity);
145         } catch (UnificationException e) {
146             int requiredArity = Types.getArity(requiredType);
147             context.getErrorLog().log(cases[0].getLhs(), "Arity is " + requiredArity + " but "
148                     + arity + " patterns have been given.");
149             setType(Types.metaVar(Kinds.STAR));
150             return this;
151         }
152         
153         effect = mfun.effect;
154         context.pushEffectUpperBound(location, mfun.effect);
155         for(Case case_ : cases)
156             case_.checkType(context, mfun.parameterTypes,  mfun.returnType);
157         context.popEffectUpperBound();
158         return this;
159     }
160     
161     @Override
162     public Expression inferType(TypingContext context) {
163         int arity = cases[0].patterns.length;
164         effect = Types.metaVar(Kinds.EFFECT);
165         context.pushEffectUpperBound(location, effect);
166         Type[] parameterTypes = new Type[arity];        
167         for(int i=0;i<parameterTypes.length;++i)
168             parameterTypes[i] = Types.metaVar(Kinds.STAR);
169         Type requiredType = Types.metaVar(Kinds.STAR);
170         for(Case case_ : cases)
171             case_.checkType(context, parameterTypes, requiredType);
172         context.popEffectUpperBound();
173         return this;
174     }
175     
176     @Override
177     public boolean isEffectful() {
178         return false;
179     }
180
181     @Override
182     public void collectEffects(THashSet<Type> effects) {
183         for(Case case_ : cases) {
184             for(Expression pattern : case_.patterns)
185                 pattern.collectEffects(effects);
186             case_.value.collectEffects(effects);
187         }
188     }
189     
190     @Override
191     public void accept(ExpressionVisitor visitor) {
192         visitor.visit(this);
193     }
194
195     @Override
196     public void forVariables(VariableProcedure procedure) {
197         for(Case case_ : cases)
198             case_.forVariables(procedure);
199     }
200     
201     @Override
202     public Expression accept(ExpressionTransformer transformer) {
203         return transformer.transform(this);
204     }
205     
206     @Override
207     public int getSyntacticFunctionArity() {
208         int result = 0;
209         for(Case case_ : cases)
210             result = Math.max(result, case_.patterns.length + case_.value.getSyntacticFunctionArity());
211         return result;
212     }
213
214 }