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;
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 chrConstraintFrames = new TIntArrayList();
ArrayList<CHRConstraintEntry> chrConstraintEntries = new ArrayList<CHRConstraintEntry>();
+ public CHRRuleset currentRuleset;
+
static class Entry {
String name;
Variable variable;
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.");
- 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.");
+ ExistentialFrame existentialFrame = getCurrentExistentialFrame();
+ if(existentialFrame == null || existentialFrame.disallowNewExistentials) {
+ errorLog.log(location, "Blank variables can be used only in queries.");
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;
}
- 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(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);
+ }
+
+ 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 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;
}
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);
}
-
- public SCLValue getBindFunction() {
- if(bindFunction == null) {
- bindFunction = getEnvironment().getValue(Names.Prelude_bind);
- }
- return bindFunction;
- }
public SCLRelation resolveRelation(long location, String name) {
SCLRelation relation = relations.get(name);
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;
+ }
}