]> gerrit.simantics Code Review - simantics/platform.git/blob
5aa77046eacac57eaaa6c499687eb07750b5339d
[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     @Override
41     public void collectVars(TObjectIntHashMap<Variable> allVars,
42             TIntHashSet vars) {
43         for(Case case_ : cases)
44             case_.collectVars(allVars, vars);
45     }
46
47     public Expression decomposeMatching() {
48         Expression[] patterns = cases[0].patterns;
49         int arity = patterns.length;
50         
51         // Simple cases
52         if(cases.length == 1 && 
53                 !(cases[0].value instanceof GuardedExpressionGroup)) {
54             boolean noMatchingNeeded = true;
55             for(int i=0;i<arity;++i)
56                 if(!(patterns[i] instanceof EVariable)) {
57                     noMatchingNeeded = false;
58                     break;
59                 }
60             if(noMatchingNeeded) {
61                 Expression decomposed = cases[0].value.decomposeMatching();
62                 Type effect = this.effect;
63                 for(int i=arity-1;i>=0;--i) {
64                     Variable var = ((EVariable)patterns[i]).getVariable(); 
65                     decomposed = new ESimpleLambda(getLocation(), var, effect, decomposed);
66                     effect = Types.NO_EFFECTS;
67                 }
68                 return decomposed;
69             }
70         }
71         
72         // Complex case
73         Variable[] vars = new Variable[arity];
74         Expression[] scrutinee = new Expression[arity];
75         for(int i=0;i<arity;++i) {
76             vars[i] = new Variable("temp" + i);
77             Type type = patterns[i].getType();
78             vars[i].setType(type);
79             scrutinee[i] = new EVariable(getLocation(), vars[i]);
80             scrutinee[i].setType(type);
81         }
82         Expression decomposed = new EMatch(getLocation(), scrutinee, cases);
83         Type curEffect = this.effect;
84         for(int i=arity-1;i>=0;--i) {            
85             decomposed = new ESimpleLambda(getLocation(), vars[i], curEffect, decomposed);            
86             curEffect = Types.NO_EFFECTS;                 
87         }
88         return decomposed;
89     }
90         
91         @Override
92         protected void updateType() throws MatchException {
93             setType(Types.functionE(Types.getTypes(cases[0].patterns), effect, cases[0].value.getType()));
94         }
95         
96         @Override
97         public Expression simplify(SimplificationContext context) {
98             return decomposeMatching().simplify(context);
99         }
100
101     @Override
102     public void collectFreeVariables(THashSet<Variable> vars) {
103         for(Case case_ : cases)
104             case_.collectFreeVariables(vars);
105     }
106
107     @Override
108     public Expression resolve(TranslationContext context) {
109         for(Case case_ : cases)
110             case_.resolve(context);
111         return this;
112     }
113     
114     @Override
115     public void setLocationDeep(long loc) {
116         if(location == Locations.NO_LOCATION) {
117             location = loc;
118             for(Case case_ : cases)
119                 case_.setLocationDeep(loc);
120         }
121     }
122     
123     @Override
124     public Expression replace(ReplaceContext context) {
125         Case[] newCases = new Case[cases.length];
126         for(int i=0;i<cases.length;++i)
127             newCases[i] = cases[i].replace(context);
128         return new ELambda(newCases);
129     }
130
131     public Case[] getCases() {
132         return cases;
133     }
134     
135     public Expression checkBasicType(TypingContext context, Type requiredType) {
136         int arity = cases[0].patterns.length;
137         MultiFunction mfun;
138         try {
139             mfun = Types.unifyFunction(requiredType, arity);
140         } catch (UnificationException e) {
141             int requiredArity = Types.getArity(requiredType);
142             context.getErrorLog().log(cases[0].getLhs(), "Arity is " + requiredArity + " but "
143                     + arity + " patterns have been given.");
144             setType(Types.metaVar(Kinds.STAR));
145             return this;
146         }
147         
148         effect = mfun.effect;
149         context.pushEffectUpperBound(location, mfun.effect);
150         for(Case case_ : cases)
151             case_.checkType(context, mfun.parameterTypes,  mfun.returnType);
152         context.popEffectUpperBound();
153         return this;
154     }
155     
156     @Override
157     public Expression inferType(TypingContext context) {
158         int arity = cases[0].patterns.length;
159         effect = Types.metaVar(Kinds.EFFECT);
160         context.pushEffectUpperBound(location, effect);
161         Type[] parameterTypes = new Type[arity];        
162         for(int i=0;i<parameterTypes.length;++i)
163             parameterTypes[i] = Types.metaVar(Kinds.STAR);
164         Type requiredType = Types.metaVar(Kinds.STAR);
165         for(Case case_ : cases)
166             case_.checkType(context, parameterTypes, requiredType);
167         context.popEffectUpperBound();
168         return this;
169     }
170     
171     @Override
172     public boolean isEffectful() {
173         return false;
174     }
175     
176     @Override
177     public void accept(ExpressionVisitor visitor) {
178         visitor.visit(this);
179     }
180     
181     @Override
182     public Expression accept(ExpressionTransformer transformer) {
183         return transformer.transform(this);
184     }
185     
186     @Override
187     public int getSyntacticFunctionArity() {
188         int result = 0;
189         for(Case case_ : cases)
190             result = Math.max(result, case_.patterns.length + case_.value.getSyntacticFunctionArity());
191         return result;
192     }
193
194 }