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