protected void processPrimary()
{
if (p.parseString("DISTINCT ") || p.parseString("distinct"))
{
// Aggregates can have "count(DISTINCT field1)"
Node distinctNode = new Node(NodeType.OPERATOR, "DISTINCT");
processExpression();
Node identifierNode = stack.pop();
distinctNode.appendChildNode(identifierNode);
stack.push(distinctNode);
return;
}
// Find any cast first, and remove from top of stack since we put after the cast component
Node castNode = null;
if (processCast())
{
castNode = stack.pop();
}
if (processCreator())
{
// "new MyClass(...)", allow chain of method invocations
boolean endOfChain = false;
while (!endOfChain)
{
if (p.parseChar('.'))
{
if (processMethod())
{
// Add method invocation as a child node of what it is invoked on
Node invokeNode = stack.pop();
Node invokedNode = stack.peek();
invokedNode.appendChildNode(invokeNode);
}
}
else
{
endOfChain = true;
}
}
if (castNode != null)
{
// TODO Add cast of creator expression
throw new NucleusException("Dont currently support compile of cast of creator expression");
}
return;
}
else if (processLiteral())
{
// Literal, allow chain of method invocations
boolean endOfChain = false;
while (!endOfChain)
{
if (p.parseChar('.'))
{
if (processMethod())
{
// Add method invocation as a child node of what it is invoked on
Node invokeNode = stack.pop();
Node invokedNode = stack.peek();
invokedNode.appendChildNode(invokeNode);
}
}
else
{
endOfChain = true;
}
}
if (castNode != null)
{
throw new NucleusException("Dont currently support compile of cast of literal expression");
// TODO Add cast of literal
}
return;
}
else if (processMethod())
{
// Static method call
if (castNode != null)
{
throw new NucleusException("Dont currently support compile of cast of static method call");
// TODO Add cast of static method call
}
return;
}
else if (processArray())
{
// Array, allow chain of method invocations
boolean endOfChain = false;
while (!endOfChain)
{
if (p.parseChar('.'))
{
if (processMethod())
{
// Add method invocation as a child node of what it is invoked on
Node invokeNode = stack.pop();
Node invokedNode = stack.peek();
invokedNode.appendChildNode(invokeNode);
}
}
else
{
endOfChain = true;
}
}
if (castNode != null)
{
throw new NucleusException("Dont currently support compile of cast of array expression");
// TODO Add cast of array
}
return;
}
int sizeBeforeBraceProcessing = stack.size();
boolean braceProcessing = false;
if (p.parseChar('('))
{
// "({expr1})"
processExpression();
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("expected ')'", p.getIndex(), p.getInput());
}
if (!p.parseChar('.'))
{
// TODO If we have a cast, then apply to the current node (with the brackets)
return;
}
// Has follow on expression "({expr1}).{expr2}" so continue
braceProcessing = true;
}
// We will have an identifier (variable, parameter, or field of candidate class)
if (!processIdentifier())
{
throw new QueryCompilerSyntaxException("Identifier expected", p.getIndex(), p.getInput());
}
// Save the stack size just before this component for use later in squashing all nodes
// down to a single Node in the stack with all others chained off from it
int size = stack.size();
if (braceProcessing)
{
size = sizeBeforeBraceProcessing+1;
}
// Generate Node tree, including chained operations
// e.g identifier.methodX().methodY().methodZ()
// -> node (IDENTIFIER) with child (INVOKE), with child (INVOKE), with child (INVOKE)
// e.g identifier.fieldX.fieldY.fieldZ
// -> node (IDENTIFIER) with child (IDENTIFIER), with child (IDENTIFIER), with child (IDENTIFIER)
while (p.parseChar('.'))
{
if (processMethod())
{
// "a.method(...)"
}
else if (processIdentifier())
{
// "a.field"
}
else
{
throw new QueryCompilerSyntaxException("Identifier expected", p.getIndex(), p.getInput());
}
}
if (castNode != null)
{
// Put the CAST as a child of the Node being cast
stack.peek().appendChildNode(castNode);
}
// For all added nodes in this block, step back and chain them. Examples :-
// a.b.c being compiled to "Node[IDENTIFIER, a] -> Node[IDENTIFIER, b] -> Node[IDENTIFIER, c]"
// ((B)a).c being compiled to "Node[IDENTIFIER, a] -> Node[CAST, B] -> Node[IDENTIFIER, c]"
while (stack.size() > size)
{
Node top = stack.pop();
Node peek = stack.peek();
getLastDescendantNodeForNode(peek).appendChildNode(top);
}
}