{
// "Object(p)", so interpret as "p"
processExpression(); // identifier at top of stack
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("')' expected", p.getIndex(), p.getInput());
}
return true;
}
else if (method.equalsIgnoreCase("MOD"))
{
// Convert to be {first} % {second}
Node modNode = new Node(NodeType.OPERATOR, "%");
processExpression(); // argument 1
Node firstNode = stack.pop();
if (!p.parseChar(','))
{
throw new QueryCompilerSyntaxException("',' expected", p.getIndex(), p.getInput());
}
processExpression(); // argument 2
Node secondNode = stack.pop();
modNode.appendChildNode(firstNode);
modNode.appendChildNode(secondNode);
stack.push(modNode);
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("')' expected", p.getIndex(), p.getInput());
}
return true;
}
else if (method.equalsIgnoreCase("TYPE"))
{
// Convert to a TYPE node with the primary as a child node
Node typeNode = new Node(NodeType.TYPE);
processExpression(); // argument
Node typePrimaryNode = stack.pop();
typeNode.appendChildNode(typePrimaryNode);
stack.push(typeNode);
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("')' expected", p.getIndex(), p.getInput());
}
return true;
}
else if (method.equalsIgnoreCase("SUBSTRING"))
{
// SUBSTRING(string_primary, simple_arithmetic_expression[, simple_arithmetic_expression])
// Convert to be {primary}.INVOKE(substring, {arg1[, arg2]})
Node invokeNode = new Node(NodeType.INVOKE, "substring");
processExpression();
Node primaryNode = stack.pop();
if (!p.parseChar(','))
{
throw new QueryCompilerSyntaxException("',' expected", p.getIndex(), p.getInput());
}
// First arg to substring(...) has origin 0, but JPQL has origin 1!
processExpression();
Node arg1 = stack.pop();
Node oneNode = new Node(NodeType.LITERAL, 1);
Node arg1Node = new Node(NodeType.OPERATOR, "-");
arg1Node.insertChildNode(arg1);
arg1Node.appendChildNode(oneNode);
if (p.parseChar(','))
{
// String.substring(arg1, arg2)
// Second arg to substring(...) has origin 0, but in JPQL is length of result!
processExpression();
Node arg2 = stack.pop();
Node arg2Node = new Node(NodeType.OPERATOR, "+");
arg2Node.appendChildNode(arg2);
arg2Node.appendChildNode(arg1Node);
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("')' expected", p.getIndex(), p.getInput());
}
primaryNode.appendChildNode(invokeNode);
invokeNode.addProperty(arg1Node);
invokeNode.addProperty(arg2Node);
stack.push(primaryNode);
return true;
}
else if (p.parseChar(')'))
{
// String.substring(arg1)
primaryNode.appendChildNode(invokeNode);
invokeNode.addProperty(arg1Node);
stack.push(primaryNode);
return true;
}
else
{
throw new QueryCompilerSyntaxException("')' expected", p.getIndex(), p.getInput());
}
}
else if (method.equalsIgnoreCase("UPPER"))
{
// UPPER(string_primary)
// Convert to be {primary}.INVOKE(toUpper)
Node invokeNode = new Node(NodeType.INVOKE, "toUpperCase");
processExpression();
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("',' expected", p.getIndex(), p.getInput());
}
Node primaryNode = stack.pop();
Node primaryRootNode = primaryNode;
while (primaryNode.getFirstChild() != null)
{
primaryNode = primaryNode.getFirstChild();
}
primaryNode.appendChildNode(invokeNode);
stack.push(primaryRootNode);
return true;
}
else if (method.equalsIgnoreCase("LOWER"))
{
// UPPER(string_primary)
// Convert to be {primary}.INVOKE(toLower)
Node invokeNode = new Node(NodeType.INVOKE, "toLowerCase");
processExpression();
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("',' expected", p.getIndex(), p.getInput());
}
Node primaryNode = stack.pop();
Node primaryRootNode = primaryNode;
while (primaryNode.getFirstChild() != null)
{
primaryNode = primaryNode.getFirstChild();
}
primaryNode.appendChildNode(invokeNode);
stack.push(primaryRootNode);
return true;
}
else if (method.equalsIgnoreCase("LENGTH"))
{
// LENGTH(string_primary)
// Convert to be {primary}.INVOKE(length)
Node invokeNode = new Node(NodeType.INVOKE, "length");
processExpression();
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("',' expected", p.getIndex(), p.getInput());
}
Node primaryNode = stack.pop();
Node primaryRootNode = primaryNode;
while (primaryNode.getFirstChild() != null)
{
primaryNode = primaryNode.getFirstChild();
}
primaryNode.appendChildNode(invokeNode);
stack.push(primaryRootNode);
return true;
}
else if (method.equalsIgnoreCase("CONCAT"))
{
// CONCAT(string_primary, string_primary[, string_primary])
// Convert to be {primary1}+{primary2}[+primary3]
processExpression();
Node prevNode = stack.pop();
while (true)
{
if (!p.parseChar(','))
{
throw new QueryCompilerSyntaxException("',' expected", p.getIndex(), p.getInput());
}
processExpression();
Node thisNode = stack.pop();
Node currentNode = new Node(NodeType.OPERATOR, "+");
currentNode.appendChildNode(prevNode);
currentNode.appendChildNode(thisNode);
if (p.parseChar(')'))
{
stack.push(currentNode);
return true;
}
prevNode = currentNode;
currentNode = null;
}
}
else if (method.equalsIgnoreCase("LOCATE"))
{
// LOCATE(string_primary, string_primary[, simple_arithmetic_expression])
// Convert to ({stringExpr}.indexOf(strExpr[, posExpr]) + 1)
processExpression();
Node searchNode = stack.pop();
Node invokeNode = new Node(NodeType.INVOKE, "indexOf");
invokeNode.addProperty(searchNode);
if (!p.parseChar(','))
{
throw new QueryCompilerSyntaxException("',' expected", p.getIndex(), p.getInput());
}
processExpression();
Node primaryNode = stack.pop();
Node primaryRootNode = primaryNode;
while (primaryNode.getFirstChild() != null)
{
primaryNode = primaryNode.getFirstChild();
}
primaryNode.appendChildNode(invokeNode);
Node oneNode = new Node(NodeType.LITERAL, 1);
if (p.parseChar(','))
{
processExpression();
Node fromPosNode = stack.pop();
Node positionNode = new Node(NodeType.OPERATOR, "-");
positionNode.appendChildNode(fromPosNode);
positionNode.appendChildNode(oneNode);
invokeNode.addProperty(positionNode);
}
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("')' expected", p.getIndex(), p.getInput());
}
Node locateNode = new Node(NodeType.OPERATOR, "+");
locateNode.appendChildNode(primaryRootNode);
locateNode.appendChildNode(oneNode);
stack.push(locateNode);
return true;
}
else if (method.equalsIgnoreCase("TRIM"))
{
// TRIM([[LEADING | TRAILING | BOTH] [trim_character] FROM] string_primary)
// Convert to be {primary}.INVOKE(trim|trimLeft|trimRight, [{trimChar}])
String methodName = "trim";
if (p.parseStringIgnoreCase("LEADING"))
{
methodName = "trimLeft";
}
else if (p.parseStringIgnoreCase("TRAILING"))
{
methodName = "trimRight";
}
else if (p.parseStringIgnoreCase("BOTH"))
{
// Default
}
Node invokeNode = new Node(NodeType.INVOKE, methodName);
Node trimCharNode = null;
processExpression();
Node next = stack.pop();
if (p.parseChar(')'))
{
// TRIM(string_primary)
next.appendChildNode(invokeNode);
stack.push(next);
return true;
}
else
{
if (next.getNodeType() == NodeType.LITERAL)
{
// TRIM(dir trimChar FROM string_primary)
trimCharNode = next;
if (p.parseStringIgnoreCase("FROM "))
{
// Ignore the FROM
}
processExpression();
next = stack.pop();
}
else if (next.getNodeType() == NodeType.IDENTIFIER)
{
// TRIM(dir FROM string_primary)
Object litValue = next.getNodeValue();
if (litValue instanceof String && ((String)litValue).equals("FROM"))
{
// FROM so ignore
processExpression(); // field expression that we are trimming
next = stack.pop();
}
else
{
throw new QueryCompilerSyntaxException("Unexpected expression", p.getIndex(), p.getInput());
}
}
else
{
// No "trimChar" or FROM, so "next" is the string expression node
}
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("')' expected", p.getIndex(), p.getInput());
}
next.appendChildNode(invokeNode);
if (trimCharNode != null)
{
invokeNode.addProperty(trimCharNode);
}
stack.push(next);
return true;
}
}
else if (method.equalsIgnoreCase("SIZE"))
{
// SIZE(collection_valued_path_expression)
// Convert to be {primary}.INVOKE(size)
Node invokeNode = new Node(NodeType.INVOKE, "size");
processExpression();
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("',' expected", p.getIndex(), p.getInput());
}
Node primaryNode = stack.pop(); // Could check type ? (Collection/Map/array)
Node primaryRootNode = primaryNode;
while (primaryNode.getFirstChild() != null)
{
primaryNode = primaryNode.getFirstChild();
}
primaryNode.appendChildNode(invokeNode);
stack.push(primaryRootNode);
return true;
}
else if (method.equalsIgnoreCase("KEY"))
{
// KEY(identification_variable)
// Convert to be {primary}.INVOKE(mapKey)
Node invokeNode = new Node(NodeType.INVOKE, "mapKey");
processExpression();
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("',' expected", p.getIndex(), p.getInput());
}
Node primaryNode = stack.pop(); // Could check type ? (Map)
Node primaryRootNode = primaryNode;
while (primaryNode.getFirstChild() != null)
{
primaryNode = primaryNode.getFirstChild();
}
primaryNode.appendChildNode(invokeNode);
stack.push(primaryRootNode);
return true;
}
else if (method.equalsIgnoreCase("VALUE"))
{
// VALUE(identification_variable)
// Convert to be {primary}.INVOKE(mapValue)
Node invokeNode = new Node(NodeType.INVOKE, "mapValue");
processExpression();
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("',' expected", p.getIndex(), p.getInput());
}
Node primaryNode = stack.pop(); // Could check type ? (Map)
Node primaryRootNode = primaryNode;
while (primaryNode.getFirstChild() != null)
{
primaryNode = primaryNode.getFirstChild();
}
primaryNode.appendChildNode(invokeNode);
stack.push(primaryRootNode);
return true;
}
else if (method.equalsIgnoreCase("ENTRY"))
{
// ENTRY(identification_variable)
// Convert to be {primary}.INVOKE(mapEntry)
Node invokeNode = new Node(NodeType.INVOKE, "mapEntry");
processExpression();
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("',' expected", p.getIndex(), p.getInput());
}
Node primaryNode = stack.pop(); // Could check type ? (Map)
Node primaryRootNode = primaryNode;
while (primaryNode.getFirstChild() != null)
{
primaryNode = primaryNode.getFirstChild();
}
primaryNode.appendChildNode(invokeNode);
stack.push(primaryRootNode);
return true;
}
else if (method.equalsIgnoreCase("YEAR"))
{
// Extension MONTH - Convert to be {primary}.INVOKE(getYear)
Node invokeNode = new Node(NodeType.INVOKE, "getYear");
processExpression();
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("',' expected", p.getIndex(), p.getInput());
}
Node primaryNode = stack.pop(); // Could check type ? (Date)
Node primaryRootNode = primaryNode;
while (primaryNode.getFirstChild() != null)
{
primaryNode = primaryNode.getFirstChild();
}
primaryNode.appendChildNode(invokeNode);
stack.push(primaryRootNode);
return true;
}
else if (method.equalsIgnoreCase("MONTH"))
{
// Extension MONTH - Convert to be {primary}.INVOKE(getMonth)
Node invokeNode = new Node(NodeType.INVOKE, "getMonth");
processExpression();
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("',' expected", p.getIndex(), p.getInput());
}
Node primaryNode = stack.pop(); // Could check type ? (Date)
Node primaryRootNode = primaryNode;
while (primaryNode.getFirstChild() != null)
{
primaryNode = primaryNode.getFirstChild();
}
primaryNode.appendChildNode(invokeNode);
stack.push(primaryRootNode);
return true;
}
else if (method.equalsIgnoreCase("DAY"))
{
// Extension DAY - Convert to be {primary}.INVOKE(getDay)
Node invokeNode = new Node(NodeType.INVOKE, "getDay");
processExpression();
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("',' expected", p.getIndex(), p.getInput());
}
Node primaryNode = stack.pop(); // Could check type ? (Date)
Node primaryRootNode = primaryNode;
while (primaryNode.getFirstChild() != null)
{
primaryNode = primaryNode.getFirstChild();
}
primaryNode.appendChildNode(invokeNode);
stack.push(primaryRootNode);
return true;
}
else if (method.equalsIgnoreCase("HOUR"))
{
// Extension HOUR - Convert to be {primary}.INVOKE(getHour)
Node invokeNode = new Node(NodeType.INVOKE, "getHour");
processExpression();
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("',' expected", p.getIndex(), p.getInput());
}
Node primaryNode = stack.pop(); // Could check type ? (Date)
Node primaryRootNode = primaryNode;
while (primaryNode.getFirstChild() != null)
{
primaryNode = primaryNode.getFirstChild();
}
primaryNode.appendChildNode(invokeNode);
stack.push(primaryRootNode);
return true;
}
else if (method.equalsIgnoreCase("MINUTE"))
{
// Extension MINUTE - Convert to be {primary}.INVOKE(getMinute)
Node invokeNode = new Node(NodeType.INVOKE, "getMinute");
processExpression();
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("',' expected", p.getIndex(), p.getInput());
}
Node primaryNode = stack.pop(); // Could check type ? (Date)
Node primaryRootNode = primaryNode;
while (primaryNode.getFirstChild() != null)
{
primaryNode = primaryNode.getFirstChild();
}
primaryNode.appendChildNode(invokeNode);
stack.push(primaryRootNode);
return true;
}
else if (method.equalsIgnoreCase("SECOND"))
{
// Extension SECOND - Convert to be {primary}.INVOKE(getSecond)
Node invokeNode = new Node(NodeType.INVOKE, "getSecond");
processExpression();
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("',' expected", p.getIndex(), p.getInput());
}
Node primaryNode = stack.pop(); // Could check type ? (Date)
Node primaryRootNode = primaryNode;
while (primaryNode.getFirstChild() != null)
{
primaryNode = primaryNode.getFirstChild();
}
primaryNode.appendChildNode(invokeNode);
stack.push(primaryRootNode);
return true;
}
else
{
// Found syntax for a method, so invoke the method
// TODO What if the method is not supported for JPQL?
Node node = new Node(NodeType.INVOKE, method);
if (!p.parseChar(')'))
{
do
{
// Argument for the method call, add as a node property
processExpression();
node.addProperty(stack.pop());
}
while (p.parseChar(','));
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("')' expected", p.getIndex(), p.getInput());
}
}
stack.push(node);
return true;
}