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