]> 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 forVariables by a visitor
[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     protected void updateType() throws MatchException {
57         throw new InternalCompilerError();
58     }
59     
60     private Type getCommonSkeleton() {
61         Type[] types = new Type[activeCount];
62         for(int i=0,j=0;i<alternatives.length;++i)
63             if(active[i])
64                 types[j++] = Types.instantiateAndStrip(alternatives[i].getType());
65         return Skeletons.commonSkeleton(context.getEnvironment(), types);
66     }
67
68     private void filterActive() {
69         THashMap<TMetaVar,Type> unifications = new THashMap<TMetaVar,Type>(); 
70         Type requiredType = getType();
71         if(DEBUG)
72             System.out.println("EAmbigious.filterActive with " + requiredType);
73         for(int i=0;i<alternatives.length;++i)
74             if(active[i]) {
75                 unifications.clear();
76                 Type alternativeType = Types.instantiateAndStrip(alternatives[i].getType());
77                 if(DEBUG)
78                     System.out.println("    " + alternativeType);
79                 if(!Skeletons.areSkeletonsCompatible(unifications, alternativeType, requiredType)) {
80                     active[i] = false;
81                     --activeCount;
82                 }
83             }
84         if(DEBUG)
85             System.out.println("    activeCount = " + activeCount);
86     }
87
88     private String getNoMatchDescription(Type requiredType) {
89         StringBuilder b = new StringBuilder();
90         b.append("Expected <");
91         requiredType.toString(new TypeUnparsingContext(), b);
92         b.append(">, but no alteratives match the type: ");
93         for(int i=0;i<alternatives.length;++i) {
94             b.append("\n    ");
95             b.append(alternatives[i]);
96             b.append(" :: ");
97             alternatives[i].getType().toString(new TypeUnparsingContext(), b);
98         }
99         b.append('.');
100         return b.toString();
101     }
102     
103     private String getAmbiguousDescription(Type requiredType) {
104         StringBuilder b = new StringBuilder();
105         b.append("Expected <");
106         requiredType.toString(new TypeUnparsingContext(), b);
107         b.append(">, but multiple values match the type: ");
108         for(int i=0;i<alternatives.length;++i) {
109             b.append("\n    ");
110             b.append(alternatives[i]);
111             b.append(" :: ");
112             alternatives[i].getType().toString(new TypeUnparsingContext(), b);
113         }
114         b.append('.');
115         return b.toString();
116     }
117
118
119     private void resolveTo(int i) {
120         if(DEBUG)
121             System.out.println("EAmbigious.resolve to " + alternatives[i]);
122         resolvedExpression = context.instantiate(alternatives[i].realize());
123         Type requiredType = getType();
124         try {
125             Types.unify(resolvedExpression.getType(), requiredType);
126         } catch (UnificationException e) {
127             context.getErrorLog().log(location, getNoMatchDescription(requiredType));
128         }
129     }
130     
131     private void listenType() {
132         if(DEBUG)
133             System.out.println("EAmbigious.listenType " + getType());
134         new TypeListener() {
135             @Override
136             public void notifyAboutChange() {
137                 if(DEBUG)
138                     System.out.println("EAmbigious.notifyAboutChange " + getType());
139                 Type requiredType = getType();
140                 filterActive();
141                 if(activeCount == 0) {
142                     context.getErrorLog().log(location, getNoMatchDescription(requiredType));
143                     return;
144                 }   
145                 else if(activeCount == 1) {
146                     for(int i=0;i<alternatives.length;++i)
147                         if(active[i]) {
148                             resolveTo(i);
149                             return;
150                         }
151                 }
152                 Type commonType = getCommonSkeleton();
153                 try {
154                     Skeletons.unifySkeletons(requiredType, commonType);
155                     listenType();
156                 } catch (UnificationException e) {
157                     context.getErrorLog().log(location, getNoMatchDescription(requiredType));
158                 }
159             }
160         }.listenSkeleton(getType());
161     }
162     
163     @Override
164     public Expression inferType(TypingContext context) {
165         this.context = context;
166         context.overloadedExpressions.add(this);
167         setType(getCommonSkeleton());
168         listenType();
169         return this;
170     }
171     
172     @Override
173     public void collectFreeVariables(THashSet<Variable> vars) {
174     }
175
176     @Override
177     public Expression resolve(TranslationContext context) {
178         throw new InternalCompilerError("EAmbiguousConstant should not exist in resolve phase.");
179     }
180
181     @Override
182     public void setLocationDeep(long loc) {
183         if(location == Locations.NO_LOCATION)
184             location = loc;
185     }
186
187     @Override
188     public void collectEffects(THashSet<Type> effects) {
189         // TODO Auto-generated method stub
190     }
191
192     @Override
193     public void accept(ExpressionVisitor visitor) {
194         // TODO Auto-generated method stub
195     }
196     
197     @Override
198     public Expression simplify(SimplificationContext context) {
199         if(resolvedExpression != null)
200             return resolvedExpression;
201         else {
202             context.getErrorLog().log(location, getAmbiguousDescription(getType()));
203             return this;
204         }
205     }
206     
207     public void assertResolved(ErrorLog errorLog) {
208         if(resolvedExpression == null)
209             errorLog.log(location, getAmbiguousDescription(getType()));
210     }
211     
212     @Override
213     public Expression accept(ExpressionTransformer transformer) {
214         return transformer.transform(this);
215     }
216
217 }