]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/contexts/TranslationContext.java
Merge "Resolve some dependency problems with SDK features"
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / contexts / TranslationContext.java
index 41f807592b7ad1de8c0b28d20183a3d4c80a3948..0331f9a50b86a7715405afc9bb37da2441d8b5b2 100644 (file)
@@ -8,11 +8,11 @@ import org.simantics.scl.compiler.common.names.Names;
 import org.simantics.scl.compiler.common.precedence.Associativity;
 import org.simantics.scl.compiler.common.precedence.Precedence;
 import org.simantics.scl.compiler.compilation.CompilationContext;
+import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
 import org.simantics.scl.compiler.elaboration.expressions.Case;
 import org.simantics.scl.compiler.elaboration.expressions.EAmbiguous;
 import org.simantics.scl.compiler.elaboration.expressions.EConstant;
-import org.simantics.scl.compiler.elaboration.expressions.EEntityTypeAnnotation;
 import org.simantics.scl.compiler.elaboration.expressions.EError;
 import org.simantics.scl.compiler.elaboration.expressions.EFieldAccess;
 import org.simantics.scl.compiler.elaboration.expressions.ELambda;
@@ -43,16 +43,28 @@ import gnu.trove.set.hash.THashSet;
 
 public class TranslationContext extends TypeTranslationContext implements EnvironmentalContext {
 
+    public static class ExistentialFrame {
+        THashSet<String> variables = new THashSet<String>(4);
+        ArrayList<Variable> blanks = new ArrayList<Variable>(2); 
+        public boolean disallowNewExistentials;
+        
+        public EVariable createBlank(long location) {
+            Variable variable = new Variable("_");
+            blanks.add(variable);
+            EVariable result = new EVariable(variable);
+            result.location = location;
+            return result;
+        }
+    }
+    
     THashMap<String, Variable> variables = new THashMap<String, Variable>();
     ArrayList<Entry> variableEntries = new ArrayList<Entry>();
     LocalEnvironment localEnvironment;
     TIntArrayList frames = new TIntArrayList();
     ArrayList<THashSet<String>> frameNameSets = new ArrayList<THashSet<String>>(); 
-    ArrayList<THashSet<String>> existentialFrames = new ArrayList<THashSet<String>>();
-    ArrayList<ArrayList<Variable>> blanksInExistentialFrame = new ArrayList<ArrayList<Variable>>();
+    ArrayList<ExistentialFrame> existentialFrames = new ArrayList<ExistentialFrame>(2);
     SCLValue bindFunction;
     
-    public EEntityTypeAnnotation currentEntityTypeAnnotation;
     public PreQuery currentPreQuery;
     
     THashMap<String, SCLRelation> relations = new THashMap<String, SCLRelation>();
@@ -111,147 +123,121 @@ public class TranslationContext extends TypeTranslationContext implements Enviro
         
         char c = name.charAt(0);
         switch(c) {
-        case '?':
-            if(existentialFrames.isEmpty()) {
-                errorLog.log(location, "Existential variables can be used only in queries.");
+        case '?': {
+            ExistentialFrame existentialFrame = getCurrentExistentialFrame();
+            if(existentialFrame == null || existentialFrame.disallowNewExistentials) {
+                errorLog.log(location, "New existential variables can be defined only in queries.");
                 return new EError(location);
             }
             variable = new Variable(name);
             variables.put(name, variable);
-            existentialFrames.get(existentialFrames.size()-1).add(name);
+            existentialFrame.variables.add(name);
             return new EVariable(variable);
-        case '_':
+        }
+        case '_': {
             if(name.length()==1) {
-                variable = new Variable("_");
-                if(blanksInExistentialFrame.isEmpty()) {
-                    errorLog.log(location, "Cannot use blank variables in this context.");
+                ExistentialFrame existentialFrame = getCurrentExistentialFrame();
+                if(existentialFrame == null || existentialFrame.disallowNewExistentials) {
+                    errorLog.log(location, "Blank variables can be used only in queries.");
                     return new EError(location);
                 }
-                blanksInExistentialFrame.get(blanksInExistentialFrame.size()-1).add(variable);
-                return new EVariable(variable);
-            }
-            break;
-        case '#':
-            if(name.length() > 1 && Character.isLetter(name.charAt(1))) {
-                if(currentEntityTypeAnnotation == null) {
-                    errorLog.log(location, "Attribute references cannot be made in this context.");
-                    return new EError(location);
-                }
-                return currentEntityTypeAnnotation.resolveAttribute(this, location, name.substring(1));
+                return existentialFrame.createBlank(location);
             }
             break;
         }
+        }
         return null;
     }
     
-    private FieldAccessor createFieldAccessor(char accessSeparator, String name) {
-        IdAccessor accessor = new IdAccessor(name);
-        accessor.accessSeparator = accessSeparator;
-        return accessor;
+    public ExistentialFrame getCurrentExistentialFrame() {
+        int size = existentialFrames.size(); 
+        if(size == 0)
+            return null;
+        else
+            return existentialFrames.get(size-1);
     }
     
     private Expression resolveFieldAccess(Expression base, int pos, String name) {
-        ArrayList<FieldAccessor> accessors = new ArrayList<FieldAccessor>(2);
         while(pos != -1) {
             int p = findSeparator(name, pos+1);
-            accessors.add(createFieldAccessor(
+            FieldAccessor accessor = new IdAccessor(
                     name.charAt(pos),
-                    name.substring(pos+1, p==-1 ? name.length() : p-1)));
+                    name.substring(pos+1, p==-1 ? name.length() : p-1));
+            base = new EFieldAccess(base, accessor);
             pos = p;
         }
-        return new EFieldAccess(base,
-                accessors.toArray(new FieldAccessor[accessors.size()]));
+        return base;
     }
     
-    private Expression resolveIn(long location, Namespace namespace, String name) {
-        SCLValue value;
-        try {
-            value = resolveValueIn(location, namespace, name);
-        } catch (AmbiguousNameException e) {
-            if(SCLCompilerConfiguration.ALLOW_OVERLOADING) {
-                EAmbiguous.Alternative[] alternatives = new EAmbiguous.Alternative[e.conflictingModules.length];
-                //System.out.println("Overloading:");
-                for(int i=0;i<e.conflictingModules.length;++i) {
-                    Name altName = Name.create(e.conflictingModules[i], e.name);
-                    //System.out.println("    " + altName);
-                    SCLValue altValue = environment.getValue(altName);
-                    alternatives[i] = new EAmbiguous.Alternative() {
-                        @Override
-                        public Type getType() {
-                            return altValue.getType();
-                        }
-    
-                        @Override
-                        public Expression realize() {
-                            EConstant expression = new EConstant(altValue);
-                            expression.location = location;
-                            return expression;
-                        }
-                        
-                        @Override
-                        public String toString() {
-                            return altValue.getName().toString().replace('/', '.');
-                        }
-                    };
-                }
-                EAmbiguous expression = new EAmbiguous(alternatives);
-                expression.location = location;
-                return expression;
-            }
-            else {
-                errorLog.log(location, e.getMessage());
-                value = null;
-            }
+    private static int findSeparator(String name, int fromIndex) {
+        ++fromIndex; // the first character (that can be #) is never a separator
+        while(fromIndex < name.length()) {
+            char c = name.charAt(fromIndex);
+            if(c == '.' || c == '#')
+                return fromIndex;
+            ++fromIndex;
         }
-        if(value == null)
-            return new EError(location);
-        return new EConstant(location, value);
+        return -1;
     }
     
-    private Expression resolveComplexNameIn(long location, Namespace namespace, int startPos, String name) {
-        int pos = name.length();
-        {
-            int hashPos = name.lastIndexOf('#');
-            if(hashPos >= 0)
-                pos = hashPos;
-        }
-        while(pos > startPos) {
-            SCLValue value;
-            try {
-                value = namespace.getValue(name.substring(startPos, pos));
-            } catch (AmbiguousNameException e) {
+    public Expression resolveValue(long location, Namespace namespace, String name) {
+        try {
+            SCLValue value = namespace.getValue(name);
+            if(value == null)
+                return null;
+            String deprecatedDescription = value.isDeprecated();
+            if(deprecatedDescription != null)
+                errorLog.logWarning(location, "Deprecated value " + value.getName().name + "." + (deprecatedDescription.isEmpty() ? "" : " " + deprecatedDescription));
+            return new EConstant(location, value);
+        } catch (AmbiguousNameException e) {
+            if(SCLCompilerConfiguration.ALLOW_OVERLOADING)
+               return resolveAmbigious(location, e.conflictingModules, name);
+            else {
                 errorLog.log(location, e.getMessage());
                 return new EError(location);
             }
-            if(value != null) {
-                Expression result = new EConstant(location, value);
-                if(pos < name.length())
-                    result = resolveFieldAccess(result, pos, name);
-                return result;
-            }
-            pos = name.lastIndexOf('.', pos-1);
         }
-        errorLog.log(location, "Couldn't resolve variable " + name + ".");
-        return new EError(location);
     }
     
-    private static int findSeparator(String name, int fromIndex) {
-        while(fromIndex < name.length()) {
-            char c = name.charAt(fromIndex);
-            if(c == '.' || c == '#')
-                return fromIndex;
-            ++fromIndex;
+    private Expression resolveAmbigious(long location, String[] conflictingModules, String name) {
+        EAmbiguous.Alternative[] alternatives = new EAmbiguous.Alternative[conflictingModules.length];
+        for(int i=0;i<conflictingModules.length;++i) {
+            Name altName = Name.create(conflictingModules[i], name);
+            SCLValue altValue = environment.getValue(altName);
+            alternatives[i] = new EAmbiguous.Alternative() {
+                @Override
+                public Type getType() {
+                    return altValue.getType();
+                }
+
+                @Override
+                public Expression realize() {
+                    EConstant expression = new EConstant(altValue);
+                    expression.location = location;
+                    return expression;
+                }
+
+                @Override
+                public String toString() {
+                    return altValue.getName().toString().replace('/', '.');
+                }
+            };
         }
-        return -1;
+        EAmbiguous expression = new EAmbiguous(alternatives);
+        expression.location = location;
+        return expression;
     }
     
-    public Expression resolveExpression(long location, String name) {
-        int p = findSeparator(name, 1 /* Initial # is not a separator */);
-        if(p == -1) {
-            Expression result = resolveLocalVariable(location, name);
+    public Expression resolveVariable(long location, Namespace namespace, String name, int begin) {
+        int end = findSeparator(name, begin);
+        String part = end == -1 ? (begin == 0 ? name : name.substring(begin)) : name.substring(begin, end);
+
+        if(begin == 0) {
+            Expression result = resolveLocalVariable(location, part);
             if(result != null)
-                return result;
+                return end == -1 ? result : resolveFieldAccess(result, end, name);
             
+            // FIXME.. support for records
             if(localEnvironment != null) {
                 result = localEnvironment.resolve(environment, name);
                 if(result != null) {
@@ -259,39 +245,82 @@ public class TranslationContext extends TypeTranslationContext implements Enviro
                     return result;
                 }
             }
-            
-            return resolveIn(location, environment.getLocalNamespace(), name);
         }
-        else {
-            if(localEnvironment != null) {
-                Expression result = localEnvironment.resolve(environment, name);
-                if(result != null) {
-                    result.setLocationDeep(location);
-                    return result;
+        if(end != -1 && name.charAt(end) == '.') {
+            Namespace childNamespace = namespace.getNamespace(part);
+            if(childNamespace != null)
+                return resolveVariable(location, childNamespace, name, end+1);
+        }
+        {
+            Expression result = null;
+            if(end != -1) {
+                for(int end2 = name.length();end2 > end;end2 = name.lastIndexOf('.', end2-1)) {
+                    part = name.substring(begin, end2);
+                    result = resolveValue(location, namespace, part);
+                    if(result != null) {
+                        end = end2 == name.length() ? -1 : end2;
+                        break;
+                    }
                 }
             }
-            
-            String prefix = name.substring(0, p);
-            Expression result = resolveLocalVariable(location, prefix);
+            if(result == null)
+                result = resolveValue(location, namespace, part);
             if(result != null)
-                return resolveFieldAccess(result, p, name);
-            
-            Namespace namespace = environment.getLocalNamespace();
-            int pos = 0;
-            while(name.charAt(p)=='.') {
-                Namespace temp = namespace.getNamespace(prefix);
-                if(temp == null)
-                    break;
-                namespace = temp;
-                pos = p+1;
-                p = findSeparator(name, pos);
-                if(p < 0)
-                    return resolveIn(location, namespace, name.substring(pos));
-                prefix = name.substring(pos, p);
+                return end == -1 ? result : resolveFieldAccess(result, end, name);
+        }
+        reportResolveFailure(location, namespace, part);
+        return new EError(location);
+    }
+    
+    private void reportResolveFailure(long location, Namespace namespace, String name) {
+        StringBuilder message = new StringBuilder();
+        message.append("Couldn't resolve ").append(name).append(".");
+
+        final THashSet<String> candidateNames = new THashSet<String>(4);
+        namespace.findValuesForPrefix("", AcceptAllNamespaceFilter.INSTANCE,
+                new TObjectProcedure<SCLValue>() {
+            @Override
+            public boolean execute(SCLValue value) {
+                if(value == null) {
+                    new Exception().printStackTrace();
+                    return true;
+                }
+                String valueName = value.getName().name;
+                if(name.equalsIgnoreCase(valueName))
+                    candidateNames.add(valueName);
+                return true;
             }
-            
-            return resolveComplexNameIn(location, namespace, pos, name);
+        });
+        if(localEnvironment != null)
+            localEnvironment.forNames(new TObjectProcedure<String>() {
+                @Override
+                public boolean execute(String valueName) {
+                    if(name.equalsIgnoreCase(valueName))
+                        candidateNames.add(valueName);
+                    return true;
+                }
+            });
+
+        if(candidateNames.size() > 0) {
+            message.append(" Did you mean ");
+            String[] ns = candidateNames.toArray(new String[candidateNames.size()]);
+            Arrays.sort(ns);
+            for(int i=0;i<ns.length;++i) {
+                if(i > 0) {
+                    message.append(", ");
+                    if(i == ns.length-1)
+                        message.append("or ");
+                }
+                message.append(ns[i]);
+            }
+            message.append('?');
         }
+
+        errorLog.log(location, message.toString());
+    }
+    
+    public Expression resolveVariable(long location, String name) {
+        return resolveVariable(location, environment.getLocalNamespace(), name, 0);
     }
     
     public Expression resolvePattern(EVar name) {
@@ -305,7 +334,7 @@ public class TranslationContext extends TypeTranslationContext implements Enviro
             return new EVariable(name.location, newVariable(name.name));
         }
         else 
-            return resolveExpression(name.location, name.name);
+            return resolveVariable(name.location, name.name);
     }
 
     /**
@@ -374,19 +403,17 @@ public class TranslationContext extends TypeTranslationContext implements Enviro
     
     public void pushExistentialFrame() {
         pushFrame();
-        existentialFrames.add(new THashSet<String>());
-        blanksInExistentialFrame.add(new ArrayList<Variable>(2));
+        existentialFrames.add(new ExistentialFrame());
     }
     
     public Variable[] popExistentialFrame() {
         popFrame();
-        THashSet<String> set = existentialFrames.remove(existentialFrames.size()-1);
-        ArrayList<Variable> blanks = blanksInExistentialFrame.remove(blanksInExistentialFrame.size()-1);
-        Variable[] result = new Variable[set.size() + blanks.size()];
+        ExistentialFrame frame = existentialFrames.remove(existentialFrames.size()-1);
+        Variable[] result = new Variable[frame.variables.size() + frame.blanks.size()];
         int i=0;
-        for(String name : set)
+        for(String name : frame.variables)
             result[i++] = variables.remove(name);
-        for(Variable blank : blanks)
+        for(Variable blank : frame.blanks)
             result[i++] = blank;
         return result;
     }
@@ -419,58 +446,6 @@ public class TranslationContext extends TypeTranslationContext implements Enviro
         else
             return prec;
     }
-
-    private SCLValue resolveValueIn(long location, Namespace namespace, final String name) throws AmbiguousNameException {
-        SCLValue value = namespace.getValue(name);
-        if(value == null) {
-            StringBuilder message = new StringBuilder();
-            message.append("Couldn't resolve variable ").append(name).append(".");
-
-            final THashSet<String> candidateNames = new THashSet<String>(4);
-            namespace.findValuesForPrefix("", AcceptAllNamespaceFilter.INSTANCE,
-                    new TObjectProcedure<SCLValue>() {
-                @Override
-                public boolean execute(SCLValue value) {
-                    if(value == null) {
-                        new Exception().printStackTrace();
-                        return true;
-                    }
-                    String valueName = value.getName().name;
-                    if(name.equalsIgnoreCase(valueName))
-                        candidateNames.add(valueName);
-                    return true;
-                }
-            });
-            if(localEnvironment != null)
-                localEnvironment.forNames(new TObjectProcedure<String>() {
-                    @Override
-                    public boolean execute(String valueName) {
-                        if(name.equalsIgnoreCase(valueName))
-                            candidateNames.add(valueName);
-                        return true;
-                    }
-                });
-
-            if(candidateNames.size() > 0) {
-                message.append(" Did you mean ");
-                String[] ns = candidateNames.toArray(new String[candidateNames.size()]);
-                Arrays.sort(ns);
-                for(int i=0;i<ns.length;++i) {
-                    if(i > 0) {
-                        message.append(", ");
-                        if(i == ns.length-1)
-                            message.append("or ");
-                    }
-                    message.append(ns[i]);
-                }
-                message.append('?');
-            }
-
-            errorLog.log(location, message.toString());
-            return null;
-        }
-        return value;
-    }
     
     public Case translateCase(Expression lhs, Expression rhs) {        
         ArrayList<Expression> parameters = new ArrayList<Expression>(4);  
@@ -568,4 +543,12 @@ public class TranslationContext extends TypeTranslationContext implements Enviro
     public SCLValue getValue(Name name) {
         return environment.getValue(name);
     }
+
+    public CHRRuleset resolveRuleset(String name) throws AmbiguousNameException {
+        return Environments.getRuleset(environment, name);
+    }
+
+    public void disallowNewExistentials() {
+        getCurrentExistentialFrame().disallowNewExistentials = true;
+    }
 }