import org.simantics.scl.compiler.common.names.Name;
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;
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.module.debug.ModuleDebugInfo;
+import org.simantics.scl.compiler.module.debug.SymbolReference;
import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
import org.simantics.scl.compiler.types.Type;
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>();
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>();
+
+ private THashSet<Expression> expandedFromWildcard;
+
+ public CHRRuleset currentRuleset;
+
+ public ModuleDebugInfo moduleDebugInfo;
+
+ private String definitionName;
+
static class Entry {
String name;
Variable variable;
}
}
- 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, String definitionName) {
+ super(compilationContext);
this.localEnvironment = localEnvironment;
+ this.moduleDebugInfo = compilationContext.moduleDebugInfo;
+ this.definitionName = definitionName;
}
public static boolean isConstructorName(String name) {
- char firstChar = name.charAt(0);
- return Character.isUpperCase(firstChar);
+ int p = name.lastIndexOf('.');
+ char firstChar = name.charAt(p<0 ? 0 : p+1);
+ return Character.isUpperCase(firstChar) || firstChar == '(';
}
/* Tries to resolve name as a local variable. It is assumed
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);
- return new EVariable(variable);
- case '_':
+ existentialFrame.variables.add(name);
+ return new EVariable(location, variable);
+ }
+ 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);
+ private Expression resolveFieldAccess(long location, Expression base, int pos, String name) {
while(pos != -1) {
int p = findSeparator(name, pos+1);
- accessors.add(createFieldAccessor(
+ int endPos = p==-1 ? name.length() : p;
+ FieldAccessor accessor = new IdAccessor(
name.charAt(pos),
- name.substring(pos+1, p==-1 ? name.length() : p-1)));
+ name.substring(pos+1, endPos));
+ accessor.location = Locations.sublocation(location, pos+1, endPos);
+ base = new EFieldAccess(base, accessor);
+ base.location = Locations.sublocation(location, 0, endPos);
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;
}
+ return -1;
+ }
+
+ public SCLValue resolveSCLValue(long location, Namespace namespace, String name) throws AmbiguousNameException {
+ SCLValue value = namespace.getValue(name);
if(value == null)
- return new EError(location);
- return new EConstant(location, value);
+ return null;
+ String deprecatedDescription = value.isDeprecated();
+ if(deprecatedDescription != null)
+ errorLog.logWarning(location, "Deprecated value " + value.getName().name + "." + (deprecatedDescription.isEmpty() ? "" : " " + deprecatedDescription));
+ if(moduleDebugInfo != null)
+ moduleDebugInfo.symbolReferences.add(new SymbolReference(value.getName(), Name.create(compilationContext.module.getName(), definitionName), location));
+ return value;
}
- 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 = resolveSCLValue(location, namespace, name);
+ if(value == null)
+ return null;
+ 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;
+ if(moduleDebugInfo != null)
+ moduleDebugInfo.symbolReferences.add(new SymbolReference(altValue.getName(), Name.create(compilationContext.module.getName(), definitionName), 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(location, result, end, name);
+ // FIXME.. support for records
if(localEnvironment != null) {
result = localEnvironment.resolve(environment, name);
if(result != null) {
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(location, result, end, name);
+ }
+ reportResolveFailure(location, namespace, part);
+ return new EError(location);
+ }
+
+ public SCLValue resolveRecordConstructor(long location, String name) throws AmbiguousNameException {
+ return resolveRecordConstructor(location, getEnvironment().getLocalNamespace(), name, 0);
+ }
+
+ public SCLValue resolveRecordConstructor(long location, Namespace namespace, String name, int begin) throws AmbiguousNameException {
+ int end = findSeparator(name, begin);
+ String part = end == -1 ? (begin == 0 ? name : name.substring(begin)) : name.substring(begin, end);
+
+ if(end != -1 && name.charAt(end) == '.') {
+ Namespace childNamespace = namespace.getNamespace(part);
+ if(childNamespace == null)
+ return null;
+ else
+ return resolveRecordConstructor(location, childNamespace, name, end+1);
+ }
+ else
+ return resolveSCLValue(location, namespace, part);
+ }
+
+ 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) {
return new EVariable(name.location, newVariable(name.name));
}
else
- return resolveExpression(name.location, name.name);
+ return resolveVariable(name.location, name.name);
}
/**
}
}
+ public void pushCHRConstraintFrame() {
+ chrConstraintFrames.add(chrConstraintEntries.size());
+ }
+
+ public void popCHRConstraintFrame(CHRRuleset ruleset) {
+ 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)
+ ruleset.addConstraint(newConstraint);
+ }
+ }
+
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;
}
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();
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);
Locations.combine(definitions.get(0).location, definitions.get(definitions.size()-1).location),
cases);
}
-
- private static final Name BIND = Name.create("Prelude", ">>=");
-
- public SCLValue getBindFunction() {
- if(bindFunction == null) {
- bindFunction = getEnvironment().getValue(BIND);
- }
- return bindFunction;
- }
public SCLRelation resolveRelation(long location, String name) {
SCLRelation relation = relations.get(name);
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);
+ }
+
+ /**
+ * Tells that new existential variables are no longer allowed in this context.
+ */
+ public void disallowNewExistentials() {
+ getCurrentExistentialFrame().disallowNewExistentials = true;
+ }
+
+ /**
+ * Marks that the expression is a result of expanding .. wildcard pattern in records.
+ */
+ public void addExpandedFromWildcard(Expression expression) {
+ if(expandedFromWildcard == null)
+ expandedFromWildcard = new THashSet<>();
+ expandedFromWildcard.add(expression);
+ }
+
+ /**
+ * Asks if the expression is a result of expanding .. wildcard pattern in records.
+ */
+ public boolean isExpandedFromWildcard(Expression expression) {
+ if(expandedFromWildcard == null)
+ return false;
+ else
+ return expandedFromWildcard.contains(expression);
+ }
}