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