if (e.getNodeName().equals("or-constraint-connective")) {
// wrap in an <or>
// first, get the contents
Set<Function> foundTerms = new LinkedHashSet<Function>();
for (Element e2 : new IterableElementList(e.getChildNodes())) {
parseNodeSide(e2, foundTerms, currentVariable, factoryFunctionMap, tracker);
}
if (foundTerms.isEmpty()) {
throw new TermParseException("Parsed an <or> but did not expect no elements contained within");
}
// now add a new <or>
Or or = new Or();
or.addAll(foundTerms);
head.add(or);
// don't re-parse contents
return;
}
if (e.getNodeName().equals("field-constraint")) {
String fieldName = e.getAttribute("field-name");
// we want to find out what the comparison is
IterableElementList literalRestrictions = new IterableElementList(e.getElementsByTagName("literal-restriction"));
IterableElementList variableRestrictions = new IterableElementList(e.getElementsByTagName("variable-restriction"));
IterableElementList quantRestrictions = new IterableElementList(e.getElementsByTagName("qualified-identifier-restriction"));
if (!literalRestrictions.isEmpty()) {
if (literalRestrictions.size() != 1) {
throw new TermParseException("Did not expect more than 1 literal restriction, found: " + literalRestrictions);
}
Element lit = (Element) literalRestrictions.item(0);
String evaluator = lit.getAttribute("evaluator");
String value = lit.getAttribute("value");
StringLiteral literalValue = new StringLiteral(value);
if (evaluator.equals("==") || evaluator.equals("!=")) {
Function f = new DoubleFunction(fieldName, currentVariable, literalValue);
if (evaluator.equals("!=")) {
// wrap it around a not
Not nf = new Not();
nf.add(f);
f = nf;
}
head.add(f);
} else {
throw new TermParseException("Expected evaluator to be '==' or '!=' but was: " + evaluator);
}
} else if (!variableRestrictions.isEmpty()) {
if (variableRestrictions.size() != 1) {
throw new TermParseException("Did not expect more than 1 variable restriction, found: " + variableRestrictions);
}
Element var = (Element) variableRestrictions.item(0);
String evaluator = var.getAttribute("evaluator");
String identifier = var.getAttribute("identifier");
if (identifier.isEmpty()) {
throw new TermParseException("Unexpected empty identifier for " + var);
}
Variable comparedTo = new NormalVariable(identifier);
if (evaluator.equals("==") || evaluator.equals("!=")) {
Function f;
if (fieldName.equals("eContainer")) {
f = new DoubleFunction("containedIn", currentVariable, comparedTo);
} else {
f = new DoubleFunction(fieldName, currentVariable, comparedTo);
}
if (evaluator.equals("!=")) {
// wrap it around a not
Not nf = new Not();
nf.add(f);
f = nf;
}
head.add(f);
} else {
throw new TermParseException("Expected evaluator to be '==' or '!=' but was: " + evaluator);
}
} else if (!quantRestrictions.isEmpty()) {
if (quantRestrictions.size() != 1) {
throw new TermParseException("Did not expect more than 1 quantified identifier restriction, found: " + quantRestrictions);
}
Element quant = (Element) quantRestrictions.item(0);
String evaluator = quant.getAttribute("evaluator");
String identifier = getTextInNode(quant);
if (identifier.isEmpty()) {
throw new TermParseException("Unexpected empty string while parsing qualified identifier restriction " + quant);
}
if (!evaluator.equals("==")) {
throw new TermParseException("Expected evaluator to be '==' but was: " + evaluator);
}
// identifier = 'o.eContainer'
// fieldName = 'eContainer'
// we want this to first create a rule "containedIn(o, z)" (z is new)
// and then connect this to fieldName "containedIn(this, z)"
String[] bits = identifier.trim().split("\\.");
if (bits.length != 2) {
throw new TermParseException("Expected two components ('a.b') in quantified expression, found: " + bits);
}
if (bits[0].isEmpty()) {
throw new TermParseException("Unexpected empty identifier for " + bits[0]);
}
if (bits[1].isEmpty()) {
throw new TermParseException("Unexpected empty field for " + bits[1]);
}
Variable newVariable = new NormalVariable(newIdentifier());
Variable from = new NormalVariable(bits[0]); // o
Function f; // new function to create
if (bits[1].equals("eContainer")) {
f = new DoubleFunction("containedIn", from, newVariable);
} else {
f = new DoubleFunction(bits[1], from, newVariable);
}
head.add(f); // add rule
// now connect the rest
Function f2;
if (fieldName.equals("eContainer")) {
f2 = new DoubleFunction("containedIn", currentVariable, newVariable);
} else {
f2 = new DoubleFunction(bits[1], currentVariable, newVariable);
}
head.add(f2);
} else {
throw new TermParseException("Did not find any restrictions for field-constant '" + fieldName + "': " + e);
}
}
if (e.getNodeName().equals("not")) {
// find the first <pattern>
IterableElementList patterns = new IterableElementList(e.getElementsByTagName("pattern"));
if (!patterns.isEmpty()) {
if (patterns.size() != 1) {
throw new TermParseException("Did not expect more than 1 pattern in <not>, found: " + patterns);
}
Element pattern = patterns.item(0);
String identifier = pattern.getAttribute("identifier");
String type = pattern.getAttribute("object-type");
if (identifier.isEmpty())
identifier = newIdentifier(); // x, x0, x1, ...
NormalVariable v = new NormalVariable(identifier);
Function f = new SingleFunction(type, v);
NotExists ne = new NotExists(v);
ne.add(f);
head.add(ne);
// add additional constraints
for (Element ee : new IterableElementList(pattern.getChildNodes())) {
parseNodeSide(ee, ne.getContents(), v, factoryFunctionMap, tracker);
}
} else {
throw new TermParseException("Expected a <not> term to contain at least one <pattern>: " + e);
}
// don't parse children
return;
}
if (e.getNodeName().equals("statement")) {
// is this a handler.generatedXXX?
IterableElementList generated = xpath(e, "assignment[set-variable]/statement/variable[@name='handler']/method[contains(@name, 'generated')]");
if (!generated.isEmpty()) {
if (generated.size() != 1) {
throw new TermParseException("Did not expect more than one generated method, found: " + generated);
}
Element generateMethod = generated.item(0);
// we found it!
// find the type of the assignment
Element setVariable = xpathFirst(e, "assignment/set-variable");
String type = setVariable.getAttribute("type");
String variableName = setVariable.getAttribute("name");
// how many arguments do we have?
IterableElementList args = xpath(generateMethod, "argument-list/variable-argument");
FactoryFunction gfunction;
if (args.size() == 2 || args.size() == 4) {
// first 2 arguments are generated by/contained in
String generatedBy = args.item(0).getAttribute("name");
String containedIn = args.item(1).getAttribute("name");
// DomainStore(f(a))
NormalVariable vGeneratedBy = new NormalVariable(generatedBy);
gfunction = new FactoryFunction(vGeneratedBy, tracker.newIndex());
SingleFunction typeCreation = new SingleFunction(type, gfunction);
head.add(typeCreation);
// generatedBy(f(a))
DoubleFunction gbyf = new DoubleFunction("generatedBy", gfunction, vGeneratedBy);
head.add(gbyf);
// containedIn(f(a), a)
NormalVariable containedInV = new NormalVariable(containedIn);
DoubleFunction cinf = new DoubleFunction("containedIn", gfunction, containedInV);
head.add(cinf);
// add this function to the map
factoryFunctionMap.put(variableName, gfunction);
} else {
throw new TermParseException("Expected 2 or 4 arguments for 'generated' method, found " + args.size() + ": " + args);
}
// linked arguments?
if (args.size() == 4) {
// next 2 arguments are linked from/to
String linkFrom = args.item(2).getAttribute("name");
String linkTo = args.item(3).getAttribute("name");
// linkedFrom(f(a), x)
NormalVariable varFrom = new NormalVariable(linkFrom);
DoubleFunction f1 = new DoubleFunction("linkedFrom", gfunction, varFrom);
head.add(f1);
// linkedTo(f(a), y)
NormalVariable varTo = new NormalVariable(linkTo);
DoubleFunction f2 = new DoubleFunction("linkedTo", gfunction, varTo);
head.add(f2);
}
// don't parse children
return;
}
}
if (e.getNodeName().equals("statement")) {
// does this have a variable?
IterableElementList variables = xpath(e, "variable");
if (variables.size() == 1) {
Element variable = variables.item(0);
String varName = variable.getAttribute("name");
// is this in the mapping of generator functions?
Variable resolved;
if (factoryFunctionMap.containsKey(varName)) {
resolved = factoryFunctionMap.get(varName);
} else {
// its a different variable
resolved = new NormalVariable(varName);
}
currentVariable = resolved;
} else if (variables.size() > 1) {
throw new TermParseException("Did not expect multiple variables for <statement>; found: " + variables);
}
}
if (e.getNodeName().equals("method")) {
// we should be operating on a current variable
String methodName = e.getAttribute("name");
try {
if (methodName.equals("setName")) {
// there should be one argument
Element arg = xpathFirst(e, "argument-list/string-argument");
Variable resArg;
if (arg.getNodeName().equals("string-argument")) {
resArg = new StringLiteral(arg.getAttribute("value"));
} else {
throw new TermParseException("Not sure what to do with an argument of type " + arg);
}
// name(f(a), 'foo')
DoubleFunction f = new DoubleFunction("name", currentVariable, resArg);
head.add(f);
} else if (methodName.equals("insert")) {
// ignore insert and do not process children
return;
}
} catch (RuntimeException ex) {
throw new RuntimeException("When trying to operate on node '" + e + "' with methodName '" + methodName + "': " + ex.getMessage(), ex);
}
}
// then children
for (Element inside : new IterableElementList(e.getChildNodes())) {
parseNodeSide(inside, head, currentVariable, factoryFunctionMap, tracker);
}
}