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