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