}
protected DynamicOperand parseDynamicOperand( TokenStream tokens,
TypeSystem typeSystem,
Source source ) {
DynamicOperand result = null;
Position pos = tokens.nextPosition();
if (tokens.canConsume('(')) {
result = parseDynamicOperand(tokens, typeSystem, source);
tokens.consume(")");
} else if (tokens.canConsume("LENGTH", "(")) {
result = new Length(parsePropertyValue(tokens, typeSystem, source));
tokens.consume(")");
} else if (tokens.canConsume("LOWER", "(")) {
result = new LowerCase(parseDynamicOperand(tokens, typeSystem, source));
tokens.consume(")");
} else if (tokens.canConsume("UPPER", "(")) {
result = new UpperCase(parseDynamicOperand(tokens, typeSystem, source));
tokens.consume(")");
} else if (tokens.canConsume("NAME", "(")) {
if (tokens.canConsume(")")) {
if (source instanceof Selector) {
return new NodeName(((Selector)source).getName());
}
String msg = GraphI18n.functionIsAmbiguous.text("NAME()", pos.getLine(), pos.getColumn());
throw new ParsingException(pos, msg);
}
result = new NodeName(parseSelectorName(tokens));
tokens.consume(")");
} else if (tokens.canConsume("LOCALNAME", "(")) {
if (tokens.canConsume(")")) {
if (source instanceof Selector) {
return new NodeLocalName(((Selector)source).getName());
}
String msg = GraphI18n.functionIsAmbiguous.text("LOCALNAME()", pos.getLine(), pos.getColumn());
throw new ParsingException(pos, msg);
}
result = new NodeLocalName(parseSelectorName(tokens));
tokens.consume(")");
} else if (tokens.canConsume("SCORE", "(")) {
if (tokens.canConsume(")")) {
if (source instanceof Selector) {
return new FullTextSearchScore(((Selector)source).getName());
}
String msg = GraphI18n.functionIsAmbiguous.text("SCORE()", pos.getLine(), pos.getColumn());
throw new ParsingException(pos, msg);
}
result = new FullTextSearchScore(parseSelectorName(tokens));
tokens.consume(")");
} else if (tokens.canConsume("DEPTH", "(")) {
if (tokens.canConsume(")")) {
if (source instanceof Selector) {
return new NodeDepth(((Selector)source).getName());
}
String msg = GraphI18n.functionIsAmbiguous.text("DEPTH()", pos.getLine(), pos.getColumn());
throw new ParsingException(pos, msg);
}
result = new NodeDepth(parseSelectorName(tokens));
tokens.consume(")");
} else if (tokens.canConsume("PATH", "(")) {
if (tokens.canConsume(")")) {
if (source instanceof Selector) {
return new NodePath(((Selector)source).getName());
}
String msg = GraphI18n.functionIsAmbiguous.text("PATH()", pos.getLine(), pos.getColumn());
throw new ParsingException(pos, msg);
}
result = new NodePath(parseSelectorName(tokens));
tokens.consume(")");
} else {
result = parsePropertyValue(tokens, typeSystem, source);
}
// Is this operand followed by an arithmetic operation ...
ArithmeticOperator arithmeticOperator = null;
if (tokens.canConsume('+')) {
arithmeticOperator = ArithmeticOperator.ADD;
} else if (tokens.canConsume('-')) {
arithmeticOperator = ArithmeticOperator.SUBTRACT;
} else if (tokens.canConsume('*')) {
arithmeticOperator = ArithmeticOperator.MULTIPLY;
} else if (tokens.canConsume('/')) {
arithmeticOperator = ArithmeticOperator.DIVIDE;
}
if (arithmeticOperator != null) {
if (tokens.matches('(')) {
// Don't use precendence, but instead use the next DynamicOperand as the RHS ...
DynamicOperand right = parseDynamicOperand(tokens, typeSystem, source);
result = new ArithmeticOperand(result, arithmeticOperator, right);
} else {
// There is no parenthesis, so use operator precedence ...
DynamicOperand right = parseDynamicOperand(tokens, typeSystem, source);
if (right instanceof ArithmeticOperand) {
// But the RHS is an arithmetic operand, so we need to use operator precedence ...
ArithmeticOperand arithRhs = (ArithmeticOperand)right;
ArithmeticOperator rhsOperator = arithRhs.getOperator();
if (arithmeticOperator.precedes(rhsOperator)) {
// This operand's operator does take precedence, so this must be computed before working with the RHS ...
DynamicOperand newRhs = arithRhs.getRight();
DynamicOperand newLhs = new ArithmeticOperand(result, arithmeticOperator, arithRhs.getLeft());
result = new ArithmeticOperand(newLhs, rhsOperator, newRhs);
} else {
result = new ArithmeticOperand(result, arithmeticOperator, right);
}
} else {