1 package org.simantics.scl.compiler.elaboration.expressions;
\r
3 import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext;
\r
4 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
\r
5 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
\r
6 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
\r
7 import org.simantics.scl.compiler.errors.Locations;
\r
8 import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator;
\r
9 import org.simantics.scl.compiler.types.Type;
\r
10 import org.simantics.scl.compiler.types.Types;
\r
11 import org.simantics.scl.compiler.types.exceptions.MatchException;
\r
12 import org.simantics.scl.compiler.types.exceptions.UnificationException;
\r
13 import org.simantics.scl.compiler.types.kinds.Kinds;
\r
14 import org.simantics.scl.compiler.types.util.MultiFunction;
\r
16 import gnu.trove.map.hash.TObjectIntHashMap;
\r
17 import gnu.trove.set.hash.THashSet;
\r
18 import gnu.trove.set.hash.TIntHashSet;
\r
20 public class ELambda extends SimplifiableExpression {
\r
21 public Case[] cases;
\r
22 Type effect = Types.NO_EFFECTS;
\r
24 public ELambda(Case[] cases) {
\r
28 public ELambda(Case case_) {
\r
29 this(new Case[] {case_});
\r
32 public ELambda(long loc, Case ... cases) {
\r
37 public ELambda(long loc, Expression pat, Expression exp) {
\r
38 this(loc, new Case(new Expression[] {pat}, exp));
\r
41 public void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs) {
\r
42 for(Case case_ : cases)
\r
43 case_.collectRefs(allRefs, refs);
\r
47 public void collectVars(TObjectIntHashMap<Variable> allVars,
\r
49 for(Case case_ : cases)
\r
50 case_.collectVars(allVars, vars);
\r
53 public Expression decomposeMatching() {
\r
54 Expression[] patterns = cases[0].patterns;
\r
55 int arity = patterns.length;
\r
58 if(cases.length == 1 &&
\r
59 !(cases[0].value instanceof GuardedExpressionGroup)) {
\r
60 boolean noMatchingNeeded = true;
\r
61 for(int i=0;i<arity;++i)
\r
62 if(!(patterns[i] instanceof EVariable)) {
\r
63 noMatchingNeeded = false;
\r
66 if(noMatchingNeeded) {
\r
67 Expression decomposed = cases[0].value.decomposeMatching();
\r
68 Type effect = this.effect;
\r
69 for(int i=arity-1;i>=0;--i) {
\r
70 Variable var = ((EVariable)patterns[i]).getVariable();
\r
71 decomposed = new ESimpleLambda(getLocation(), var, effect, decomposed);
\r
72 effect = Types.NO_EFFECTS;
\r
79 Variable[] vars = new Variable[arity];
\r
80 Expression[] scrutinee = new Expression[arity];
\r
81 for(int i=0;i<arity;++i) {
\r
82 vars[i] = new Variable("temp" + i);
\r
83 Type type = patterns[i].getType();
\r
84 vars[i].setType(type);
\r
85 scrutinee[i] = new EVariable(getLocation(), vars[i]);
\r
86 scrutinee[i].setType(type);
\r
88 Expression decomposed = new EMatch(getLocation(), scrutinee, cases);
\r
89 Type curEffect = this.effect;
\r
90 for(int i=arity-1;i>=0;--i) {
\r
91 decomposed = new ESimpleLambda(getLocation(), vars[i], curEffect, decomposed);
\r
92 curEffect = Types.NO_EFFECTS;
\r
98 protected void updateType() throws MatchException {
\r
99 setType(Types.functionE(Types.getTypes(cases[0].patterns), effect, cases[0].value.getType()));
\r
103 public Expression simplify(SimplificationContext context) {
\r
104 return decomposeMatching().simplify(context);
\r
108 public void collectFreeVariables(THashSet<Variable> vars) {
\r
109 for(Case case_ : cases)
\r
110 case_.collectFreeVariables(vars);
\r
114 public Expression resolve(TranslationContext context) {
\r
115 for(Case case_ : cases)
\r
116 case_.resolve(context);
\r
121 public void setLocationDeep(long loc) {
\r
122 if(location == Locations.NO_LOCATION) {
\r
124 for(Case case_ : cases)
\r
125 case_.setLocationDeep(loc);
\r
130 public Expression replace(ReplaceContext context) {
\r
131 Case[] newCases = new Case[cases.length];
\r
132 for(int i=0;i<cases.length;++i)
\r
133 newCases[i] = cases[i].replace(context);
\r
134 return new ELambda(newCases);
\r
137 public Case[] getCases() {
\r
141 public Expression checkBasicType(TypingContext context, Type requiredType) {
\r
142 int arity = cases[0].patterns.length;
\r
143 MultiFunction mfun;
\r
145 mfun = Types.unifyFunction(requiredType, arity);
\r
146 } catch (UnificationException e) {
\r
147 int requiredArity = Types.getArity(requiredType);
\r
148 context.getErrorLog().log(cases[0].getLhs(), "Arity is " + requiredArity + " but "
\r
149 + arity + " patterns have been given.");
\r
150 setType(Types.metaVar(Kinds.STAR));
\r
154 effect = mfun.effect;
\r
155 context.pushEffectUpperBound(location, mfun.effect);
\r
156 for(Case case_ : cases)
\r
157 case_.checkType(context, mfun.parameterTypes, mfun.returnType);
\r
158 context.popEffectUpperBound();
\r
163 public Expression inferType(TypingContext context) {
\r
164 int arity = cases[0].patterns.length;
\r
165 effect = Types.metaVar(Kinds.EFFECT);
\r
166 context.pushEffectUpperBound(location, effect);
\r
167 Type[] parameterTypes = new Type[arity];
\r
168 for(int i=0;i<parameterTypes.length;++i)
\r
169 parameterTypes[i] = Types.metaVar(Kinds.STAR);
\r
170 Type requiredType = Types.metaVar(Kinds.STAR);
\r
171 for(Case case_ : cases)
\r
172 case_.checkType(context, parameterTypes, requiredType);
\r
173 context.popEffectUpperBound();
\r
178 public Expression decorate(ExpressionDecorator decorator) {
\r
179 if(decorator.decorateSubstructure(this))
\r
180 for(Case case_ : cases)
\r
181 case_.decorate(decorator);
\r
182 return decorator.decorate(this);
\r
186 public boolean isEffectful() {
\r
191 public void collectEffects(THashSet<Type> effects) {
\r
192 for(Case case_ : cases) {
\r
193 for(Expression pattern : case_.patterns)
\r
194 pattern.collectEffects(effects);
\r
195 case_.value.collectEffects(effects);
\r
200 public void accept(ExpressionVisitor visitor) {
\r
201 visitor.visit(this);
\r
205 public void forVariables(VariableProcedure procedure) {
\r
206 for(Case case_ : cases)
\r
207 case_.forVariables(procedure);
\r
211 public Expression accept(ExpressionTransformer transformer) {
\r
212 return transformer.transform(this);
\r