]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EAmbiguous.java
migrated to svn revision 33108
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / expressions / EAmbiguous.java
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EAmbiguous.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EAmbiguous.java
new file mode 100644 (file)
index 0000000..6121a57
--- /dev/null
@@ -0,0 +1,227 @@
+package org.simantics.scl.compiler.elaboration.expressions;
+
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
+import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
+import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
+import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
+import org.simantics.scl.compiler.errors.ErrorLog;
+import org.simantics.scl.compiler.errors.Locations;
+import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator;
+import org.simantics.scl.compiler.types.Skeletons;
+import org.simantics.scl.compiler.types.TMetaVar;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.compiler.types.Types;
+import org.simantics.scl.compiler.types.exceptions.MatchException;
+import org.simantics.scl.compiler.types.exceptions.UnificationException;
+import org.simantics.scl.compiler.types.util.TypeListener;
+import org.simantics.scl.compiler.types.util.TypeUnparsingContext;
+
+import gnu.trove.map.hash.THashMap;
+import gnu.trove.map.hash.TObjectIntHashMap;
+import gnu.trove.set.hash.THashSet;
+import gnu.trove.set.hash.TIntHashSet;
+
+public class EAmbiguous extends SimplifiableExpression {
+    public static final boolean DEBUG = false;
+    
+    Alternative[] alternatives;
+    boolean[] active;
+    int activeCount;
+    transient TypingContext context;
+    Expression resolvedExpression;
+    
+    public abstract static class Alternative {
+        public abstract Type getType();
+        public abstract Expression realize();
+    }
+    
+    public EAmbiguous(Alternative[] alternatives) {
+        this.alternatives = alternatives;
+        this.active = new boolean[alternatives.length];
+        for(int i=0;i<alternatives.length;++i)
+            this.active[i] = true;
+        this.activeCount = alternatives.length;
+    }
+
+    @Override
+    public void collectRefs(TObjectIntHashMap<Object> allRefs,
+            TIntHashSet refs) {
+    }
+
+    @Override
+    public void collectVars(TObjectIntHashMap<Variable> allVars,
+            TIntHashSet vars) {
+    }
+
+    @Override
+    public void forVariables(VariableProcedure procedure) {
+    }
+
+    @Override
+    protected void updateType() throws MatchException {
+        throw new InternalCompilerError();
+    }
+    
+    private Type getCommonSkeleton() {
+        Type[] types = new Type[activeCount];
+        for(int i=0,j=0;i<alternatives.length;++i)
+            if(active[i])
+                types[j++] = Types.instantiateAndStrip(alternatives[i].getType());
+        return Skeletons.commonSkeleton(context.getEnvironment(), types);
+    }
+
+    private void filterActive() {
+        THashMap<TMetaVar,Type> unifications = new THashMap<TMetaVar,Type>(); 
+        Type requiredType = getType();
+        if(DEBUG)
+            System.out.println("EAmbigious.filterActive with " + requiredType);
+        for(int i=0;i<alternatives.length;++i)
+            if(active[i]) {
+                unifications.clear();
+                Type alternativeType = Types.instantiateAndStrip(alternatives[i].getType());
+                if(DEBUG)
+                    System.out.println("    " + alternativeType);
+                if(!Skeletons.areSkeletonsCompatible(unifications, alternativeType, requiredType)) {
+                    active[i] = false;
+                    --activeCount;
+                }
+            }
+        if(DEBUG)
+            System.out.println("    activeCount = " + activeCount);
+    }
+
+    private String getNoMatchDescription(Type requiredType) {
+        StringBuilder b = new StringBuilder();
+        b.append("Expected <");
+        requiredType.toString(new TypeUnparsingContext(), b);
+        b.append(">, but no alteratives match the type: ");
+        for(int i=0;i<alternatives.length;++i) {
+            b.append("\n    ");
+            b.append(alternatives[i]);
+            b.append(" :: ");
+            alternatives[i].getType().toString(new TypeUnparsingContext(), b);
+        }
+        b.append('.');
+        return b.toString();
+    }
+    
+    private String getAmbiguousDescription(Type requiredType) {
+        StringBuilder b = new StringBuilder();
+        b.append("Expected <");
+        requiredType.toString(new TypeUnparsingContext(), b);
+        b.append(">, but multiple values match the type: ");
+        for(int i=0;i<alternatives.length;++i) {
+            b.append("\n    ");
+            b.append(alternatives[i]);
+            b.append(" :: ");
+            alternatives[i].getType().toString(new TypeUnparsingContext(), b);
+        }
+        b.append('.');
+        return b.toString();
+    }
+
+
+    private void resolveTo(int i) {
+        if(DEBUG)
+            System.out.println("EAmbigious.resolve to " + alternatives[i]);
+        resolvedExpression = context.instantiate(alternatives[i].realize());
+        Type requiredType = getType();
+        try {
+            Types.unify(resolvedExpression.getType(), requiredType);
+        } catch (UnificationException e) {
+            context.getErrorLog().log(location, getNoMatchDescription(requiredType));
+        }
+    }
+    
+    private void listenType() {
+        if(DEBUG)
+            System.out.println("EAmbigious.listenType " + getType());
+        new TypeListener() {
+            @Override
+            public void notifyAboutChange() {
+                if(DEBUG)
+                    System.out.println("EAmbigious.notifyAboutChange " + getType());
+                Type requiredType = getType();
+                filterActive();
+                if(activeCount == 0) {
+                    context.getErrorLog().log(location, getNoMatchDescription(requiredType));
+                    return;
+                }   
+                else if(activeCount == 1) {
+                    for(int i=0;i<alternatives.length;++i)
+                        if(active[i]) {
+                            resolveTo(i);
+                            return;
+                        }
+                }
+                Type commonType = getCommonSkeleton();
+                try {
+                    Skeletons.unifySkeletons(requiredType, commonType);
+                    listenType();
+                } catch (UnificationException e) {
+                    context.getErrorLog().log(location, getNoMatchDescription(requiredType));
+                }
+            }
+        }.listenSkeleton(getType());
+    }
+    
+    @Override
+    public Expression inferType(TypingContext context) {
+        this.context = context;
+        context.overloadedExpressions.add(this);
+        setType(getCommonSkeleton());
+        listenType();
+        return this;
+    }
+    
+    @Override
+    public void collectFreeVariables(THashSet<Variable> vars) {
+    }
+
+    @Override
+    public Expression resolve(TranslationContext context) {
+        throw new InternalCompilerError("EAmbiguousConstant should not exist in resolve phase.");
+    }
+
+    @Override
+    public void setLocationDeep(long loc) {
+        if(location == Locations.NO_LOCATION)
+            location = loc;
+    }
+
+    @Override
+    public Expression decorate(ExpressionDecorator decorator) {
+        return this;
+    }
+
+    @Override
+    public void collectEffects(THashSet<Type> effects) {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public void accept(ExpressionVisitor visitor) {
+        // TODO Auto-generated method stub
+    }
+    
+    @Override
+    public Expression simplify(SimplificationContext context) {
+        if(resolvedExpression != null)
+            return resolvedExpression;
+        else {
+            context.getErrorLog().log(location, getAmbiguousDescription(getType()));
+            return this;
+        }
+    }
+    
+    public void assertResolved(ErrorLog errorLog) {
+        if(resolvedExpression == null)
+            errorLog.log(location, getAmbiguousDescription(getType()));
+    }
+    
+    @Override
+    public Expression accept(ExpressionTransformer transformer) {
+        return transformer.transform(this);
+    }
+
+}