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