]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EAmbiguous.java
(refs #7375) Replaced ExpressionDecorator by ExpressionTransformer
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / expressions / EAmbiguous.java
1 package org.simantics.scl.compiler.elaboration.expressions;
2
3 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
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.ErrorLog;
8 import org.simantics.scl.compiler.errors.Locations;
9 import org.simantics.scl.compiler.types.Skeletons;
10 import org.simantics.scl.compiler.types.TMetaVar;
11 import org.simantics.scl.compiler.types.Type;
12 import org.simantics.scl.compiler.types.Types;
13 import org.simantics.scl.compiler.types.exceptions.MatchException;
14 import org.simantics.scl.compiler.types.exceptions.UnificationException;
15 import org.simantics.scl.compiler.types.util.TypeListener;
16 import org.simantics.scl.compiler.types.util.TypeUnparsingContext;
17
18 import gnu.trove.map.hash.THashMap;
19 import gnu.trove.map.hash.TObjectIntHashMap;
20 import gnu.trove.set.hash.THashSet;
21 import gnu.trove.set.hash.TIntHashSet;
22
23 public class EAmbiguous extends SimplifiableExpression {
24     public static final boolean DEBUG = false;
25     
26     Alternative[] alternatives;
27     boolean[] active;
28     int activeCount;
29     transient TypingContext context;
30     Expression resolvedExpression;
31     
32     public abstract static class Alternative {
33         public abstract Type getType();
34         public abstract Expression realize();
35     }
36     
37     public EAmbiguous(Alternative[] alternatives) {
38         this.alternatives = alternatives;
39         this.active = new boolean[alternatives.length];
40         for(int i=0;i<alternatives.length;++i)
41             this.active[i] = true;
42         this.activeCount = alternatives.length;
43     }
44
45     @Override
46     public void collectRefs(TObjectIntHashMap<Object> allRefs,
47             TIntHashSet refs) {
48     }
49
50     @Override
51     public void collectVars(TObjectIntHashMap<Variable> allVars,
52             TIntHashSet vars) {
53     }
54
55     @Override
56     public void forVariables(VariableProcedure procedure) {
57     }
58
59     @Override
60     protected void updateType() throws MatchException {
61         throw new InternalCompilerError();
62     }
63     
64     private Type getCommonSkeleton() {
65         Type[] types = new Type[activeCount];
66         for(int i=0,j=0;i<alternatives.length;++i)
67             if(active[i])
68                 types[j++] = Types.instantiateAndStrip(alternatives[i].getType());
69         return Skeletons.commonSkeleton(context.getEnvironment(), types);
70     }
71
72     private void filterActive() {
73         THashMap<TMetaVar,Type> unifications = new THashMap<TMetaVar,Type>(); 
74         Type requiredType = getType();
75         if(DEBUG)
76             System.out.println("EAmbigious.filterActive with " + requiredType);
77         for(int i=0;i<alternatives.length;++i)
78             if(active[i]) {
79                 unifications.clear();
80                 Type alternativeType = Types.instantiateAndStrip(alternatives[i].getType());
81                 if(DEBUG)
82                     System.out.println("    " + alternativeType);
83                 if(!Skeletons.areSkeletonsCompatible(unifications, alternativeType, requiredType)) {
84                     active[i] = false;
85                     --activeCount;
86                 }
87             }
88         if(DEBUG)
89             System.out.println("    activeCount = " + activeCount);
90     }
91
92     private String getNoMatchDescription(Type requiredType) {
93         StringBuilder b = new StringBuilder();
94         b.append("Expected <");
95         requiredType.toString(new TypeUnparsingContext(), b);
96         b.append(">, but no alteratives match the type: ");
97         for(int i=0;i<alternatives.length;++i) {
98             b.append("\n    ");
99             b.append(alternatives[i]);
100             b.append(" :: ");
101             alternatives[i].getType().toString(new TypeUnparsingContext(), b);
102         }
103         b.append('.');
104         return b.toString();
105     }
106     
107     private String getAmbiguousDescription(Type requiredType) {
108         StringBuilder b = new StringBuilder();
109         b.append("Expected <");
110         requiredType.toString(new TypeUnparsingContext(), b);
111         b.append(">, but multiple values match the type: ");
112         for(int i=0;i<alternatives.length;++i) {
113             b.append("\n    ");
114             b.append(alternatives[i]);
115             b.append(" :: ");
116             alternatives[i].getType().toString(new TypeUnparsingContext(), b);
117         }
118         b.append('.');
119         return b.toString();
120     }
121
122
123     private void resolveTo(int i) {
124         if(DEBUG)
125             System.out.println("EAmbigious.resolve to " + alternatives[i]);
126         resolvedExpression = context.instantiate(alternatives[i].realize());
127         Type requiredType = getType();
128         try {
129             Types.unify(resolvedExpression.getType(), requiredType);
130         } catch (UnificationException e) {
131             context.getErrorLog().log(location, getNoMatchDescription(requiredType));
132         }
133     }
134     
135     private void listenType() {
136         if(DEBUG)
137             System.out.println("EAmbigious.listenType " + getType());
138         new TypeListener() {
139             @Override
140             public void notifyAboutChange() {
141                 if(DEBUG)
142                     System.out.println("EAmbigious.notifyAboutChange " + getType());
143                 Type requiredType = getType();
144                 filterActive();
145                 if(activeCount == 0) {
146                     context.getErrorLog().log(location, getNoMatchDescription(requiredType));
147                     return;
148                 }   
149                 else if(activeCount == 1) {
150                     for(int i=0;i<alternatives.length;++i)
151                         if(active[i]) {
152                             resolveTo(i);
153                             return;
154                         }
155                 }
156                 Type commonType = getCommonSkeleton();
157                 try {
158                     Skeletons.unifySkeletons(requiredType, commonType);
159                     listenType();
160                 } catch (UnificationException e) {
161                     context.getErrorLog().log(location, getNoMatchDescription(requiredType));
162                 }
163             }
164         }.listenSkeleton(getType());
165     }
166     
167     @Override
168     public Expression inferType(TypingContext context) {
169         this.context = context;
170         context.overloadedExpressions.add(this);
171         setType(getCommonSkeleton());
172         listenType();
173         return this;
174     }
175     
176     @Override
177     public void collectFreeVariables(THashSet<Variable> vars) {
178     }
179
180     @Override
181     public Expression resolve(TranslationContext context) {
182         throw new InternalCompilerError("EAmbiguousConstant should not exist in resolve phase.");
183     }
184
185     @Override
186     public void setLocationDeep(long loc) {
187         if(location == Locations.NO_LOCATION)
188             location = loc;
189     }
190
191     @Override
192     public void collectEffects(THashSet<Type> effects) {
193         // TODO Auto-generated method stub
194     }
195
196     @Override
197     public void accept(ExpressionVisitor visitor) {
198         // TODO Auto-generated method stub
199     }
200     
201     @Override
202     public Expression simplify(SimplificationContext context) {
203         if(resolvedExpression != null)
204             return resolvedExpression;
205         else {
206             context.getErrorLog().log(location, getAmbiguousDescription(getType()));
207             return this;
208         }
209     }
210     
211     public void assertResolved(ErrorLog errorLog) {
212         if(resolvedExpression == null)
213             errorLog.log(location, getAmbiguousDescription(getType()));
214     }
215     
216     @Override
217     public Expression accept(ExpressionTransformer transformer) {
218         return transformer.transform(this);
219     }
220
221 }