]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/contexts/TranslationContext.java
(refs #7250) CHR rules modularization (first working version)
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / contexts / TranslationContext.java
index 961fa902b9db552469b998f2e30e8255f806dcc1..d9746bb04c1d9a2524e82a03193c80a6773ee450 100644 (file)
@@ -1,19 +1,18 @@
 package org.simantics.scl.compiler.elaboration.contexts;
 
-import gnu.trove.list.array.TIntArrayList;
-import gnu.trove.map.hash.THashMap;
-import gnu.trove.procedure.TObjectProcedure;
-import gnu.trove.set.hash.THashSet;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 
 import org.simantics.scl.compiler.common.names.Name;
+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;
@@ -28,14 +27,19 @@ import org.simantics.scl.compiler.elaboration.modules.SCLValue;
 import org.simantics.scl.compiler.elaboration.query.pre.PreQuery;
 import org.simantics.scl.compiler.elaboration.relations.SCLRelation;
 import org.simantics.scl.compiler.environment.AmbiguousNameException;
-import org.simantics.scl.compiler.environment.Environment;
 import org.simantics.scl.compiler.environment.Environments;
 import org.simantics.scl.compiler.environment.LocalEnvironment;
 import org.simantics.scl.compiler.environment.Namespace;
 import org.simantics.scl.compiler.environment.filter.AcceptAllNamespaceFilter;
-import org.simantics.scl.compiler.errors.ErrorLog;
 import org.simantics.scl.compiler.errors.Locations;
 import org.simantics.scl.compiler.internal.parsing.declarations.DValueAst;
+import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
+import org.simantics.scl.compiler.types.Type;
+
+import gnu.trove.list.array.TIntArrayList;
+import gnu.trove.map.hash.THashMap;
+import gnu.trove.procedure.TObjectProcedure;
+import gnu.trove.set.hash.THashSet;
 
 public class TranslationContext extends TypeTranslationContext implements EnvironmentalContext {
 
@@ -48,13 +52,16 @@ public class TranslationContext extends TypeTranslationContext implements Enviro
     ArrayList<ArrayList<Variable>> blanksInExistentialFrame = new ArrayList<ArrayList<Variable>>();
     SCLValue bindFunction;
     
-    public EEntityTypeAnnotation currentEntityTypeAnnotation;
     public PreQuery currentPreQuery;
     
     THashMap<String, SCLRelation> relations = new THashMap<String, SCLRelation>();
     TIntArrayList relationFrames = new TIntArrayList();
     ArrayList<RelationEntry> relationEntries = new ArrayList<RelationEntry>();
     
+    THashMap<String, CHRConstraint> chrConstraints = new THashMap<String, CHRConstraint>();
+    TIntArrayList chrConstraintFrames = new TIntArrayList();
+    ArrayList<CHRConstraintEntry> chrConstraintEntries = new ArrayList<CHRConstraintEntry>();
+    
     static class Entry {
         String name;
         Variable variable;
@@ -73,14 +80,23 @@ public class TranslationContext extends TypeTranslationContext implements Enviro
         }
     }
     
-    public TranslationContext(ErrorLog errorLog, 
-            Environment environment, LocalEnvironment localEnvironment) {
-        super(errorLog, environment);
+    static class CHRConstraintEntry {
+        String name;
+        CHRConstraint constraint;
+        public CHRConstraintEntry(String name, CHRConstraint constraint) {
+            this.name = name;
+            this.constraint = constraint;
+        }
+    }
+    
+    public TranslationContext(CompilationContext compilationContext, LocalEnvironment localEnvironment) {
+        super(compilationContext);
         this.localEnvironment = localEnvironment;
     }
     
     public static boolean isConstructorName(String name) {
-        char firstChar = name.charAt(0);
+        int p = name.lastIndexOf('.');
+        char firstChar = name.charAt(p<0 ? 0 : p+1);
         return Character.isUpperCase(firstChar);
     }
     
@@ -114,89 +130,91 @@ public class TranslationContext extends TypeTranslationContext implements Enviro
                 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));
-            }
-            break;
         }
         return null;
     }
     
-    private FieldAccessor createFieldAccessor(char accessSeparator, String name) {
-        IdAccessor accessor = new IdAccessor(name);
-        accessor.accessSeparator = accessSeparator;
-        return accessor;
-    }
-    
     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 = resolveValueIn(location, namespace, name);
-        if(value == null)
-            return new EError(location);
-        return new EConstant(location, value);
+    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;
+        }
+        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) {
@@ -204,39 +222,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) {
@@ -250,7 +311,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);
     }
 
     /**
@@ -297,6 +358,26 @@ public class TranslationContext extends TypeTranslationContext implements Enviro
         }
     }
     
+    public void pushCHRConstraintFrame() {
+        chrConstraintFrames.add(chrConstraintEntries.size());
+    }
+    
+    public void popCHRConstraintFrame(ArrayList<CHRConstraint> constraints) {
+        int frame = chrConstraintFrames.removeAt(chrConstraintFrames.size()-1);
+        int i = chrConstraintEntries.size();
+        while(i > frame) {
+            --i;
+            CHRConstraintEntry entry = chrConstraintEntries.remove(i);
+            CHRConstraint newConstraint;
+            if(entry.constraint == null)
+                newConstraint = chrConstraints.remove(entry.name);
+            else
+                newConstraint = chrConstraints.put(entry.name, entry.constraint);
+            if(newConstraint.implicitlyDeclared)
+                constraints.add(newConstraint);
+        }
+    }
+    
     public void pushExistentialFrame() {
         pushFrame();
         existentialFrames.add(new THashSet<String>());
@@ -331,6 +412,11 @@ public class TranslationContext extends TypeTranslationContext implements Enviro
         SCLRelation oldRelation = relations.put(name, relation);
         relationEntries.add(new RelationEntry(name, oldRelation));
     }
+    
+    public void newCHRConstraint(String name, CHRConstraint constraint) {
+        CHRConstraint oldConstraint = chrConstraints.put(name, constraint);
+        chrConstraintEntries.add(new CHRConstraintEntry(name, oldConstraint));
+    }
             
     public Precedence getPrecedence(Name op) {
         Precedence prec = environment.getValue(op).getPrecedence();
@@ -339,63 +425,6 @@ public class TranslationContext extends TypeTranslationContext implements Enviro
         else
             return prec;
     }
-
-    private SCLValue resolveValueIn(long location, Namespace namespace, final String name) {
-        try {
-            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;
-        } catch (AmbiguousNameException e) {
-            errorLog.log(location, e.getMessage());
-            return null;
-        }
-    }
     
     public Case translateCase(Expression lhs, Expression rhs) {        
         ArrayList<Expression> parameters = new ArrayList<Expression>(4);  
@@ -460,11 +489,9 @@ public class TranslationContext extends TypeTranslationContext implements Enviro
                 cases);
     }
     
-    private static final Name BIND = Name.create("Prelude", ">>=");
-    
     public SCLValue getBindFunction() {
         if(bindFunction == null) {
-            bindFunction = getEnvironment().getValue(BIND);
+            bindFunction = getEnvironment().getValue(Names.Prelude_bind);
         }
         return bindFunction;
     }
@@ -486,9 +513,17 @@ public class TranslationContext extends TypeTranslationContext implements Enviro
             return null;
         }
     }
+    
+    public CHRConstraint resolveCHRConstraint(String name) {
+        return chrConstraints.get(name);
+    }
 
     @Override
     public SCLValue getValue(Name name) {
         return environment.getValue(name);
     }
+
+    public CHRRuleset resolveRuleset(String name) throws AmbiguousNameException {
+        return Environments.getRuleset(environment, name);
+    }
 }