1 package org.simantics.scl.compiler.elaboration.expressions;
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;
15 import gnu.trove.map.hash.TObjectIntHashMap;
16 import gnu.trove.set.hash.THashSet;
17 import gnu.trove.set.hash.TIntHashSet;
19 public class ELambda extends SimplifiableExpression {
21 Type effect = Types.NO_EFFECTS;
23 public ELambda(Case[] cases) {
27 public ELambda(Case case_) {
28 this(new Case[] {case_});
31 public ELambda(long loc, Case ... cases) {
36 public ELambda(long loc, Expression pat, Expression exp) {
37 this(loc, new Case(new Expression[] {pat}, exp));
41 public void collectVars(TObjectIntHashMap<Variable> allVars,
43 for(Case case_ : cases)
44 case_.collectVars(allVars, vars);
47 public Expression decomposeMatching() {
48 Expression[] patterns = cases[0].patterns;
49 int arity = patterns.length;
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;
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;
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);
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;
92 protected void updateType() throws MatchException {
93 setType(Types.functionE(Types.getTypes(cases[0].patterns), effect, cases[0].value.getType()));
97 public Expression simplify(SimplificationContext context) {
98 return decomposeMatching().simplify(context);
102 public void collectFreeVariables(THashSet<Variable> vars) {
103 for(Case case_ : cases)
104 case_.collectFreeVariables(vars);
108 public Expression resolve(TranslationContext context) {
109 for(Case case_ : cases)
110 case_.resolve(context);
115 public void setLocationDeep(long loc) {
116 if(location == Locations.NO_LOCATION) {
118 for(Case case_ : cases)
119 case_.setLocationDeep(loc);
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);
131 public Case[] getCases() {
135 public Expression checkBasicType(TypingContext context, Type requiredType) {
136 int arity = cases[0].patterns.length;
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));
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();
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();
172 public boolean isEffectful() {
177 public void accept(ExpressionVisitor visitor) {
182 public Expression accept(ExpressionTransformer transformer) {
183 return transformer.transform(this);
187 public int getSyntacticFunctionArity() {
189 for(Case case_ : cases)
190 result = Math.max(result, case_.patterns.length + case_.value.getSyntacticFunctionArity());