private Expression compilePrimaryExpression(Node node)
{
if (node.getNodeType() == Node.IDENTIFIER)
{
Node currentNode = node;
List tupple = new ArrayList();
Expression currentExpr = null;
while (currentNode != null)
{
tupple.add(currentNode.getNodeValue());
if (currentNode.getNodeType() == Node.INVOKE)
{
if (currentExpr == null && tupple.size() > 1)
{
// Check for starting with parameter/variable
String first = (String)tupple.get(0);
Symbol firstSym = symtbl.getSymbol(first);
if (firstSym != null)
{
if (firstSym.getType() == Symbol.PARAMETER)
{
currentExpr = new ParameterExpression(symtbl, first, -1);
if (tupple.size() > 2)
{
currentExpr = new PrimaryExpression(symtbl, currentExpr, tupple.subList(1, tupple.size()-1));
}
}
else if (firstSym.getType() == Symbol.VARIABLE)
{
currentExpr = new VariableExpression(symtbl, first);
if (tupple.size() > 2)
{
currentExpr = new PrimaryExpression(symtbl, currentExpr, tupple.subList(1, tupple.size()-1));
}
}
}
if (currentExpr == null)
{
currentExpr = new PrimaryExpression(symtbl, tupple.subList(0, tupple.size()-1));
}
}
String methodName = (String)tupple.get(tupple.size()-1);
if (currentExpr instanceof PrimaryExpression)
{
// TODO Add plugin point to define aliases for methods for the query language
// ExpressionCompiler would need to know the query language name
String id = ((PrimaryExpression)currentExpr).getId();
if (id.equals("Math") || id.equals("java.lang.Math"))
{
methodName = "Math." + methodName;
currentExpr = null;
}
else if (id.equals("JDOHelper") || id.equals("javax.jdo.JDOHelper"))
{
methodName = "JDOHelper." + methodName;
currentExpr = null;
}
}
List parameterExprs = getExpressionsForPropertiesOfNode(currentNode);
currentExpr = new InvokeExpression(symtbl, currentExpr, methodName, parameterExprs);
currentNode = currentNode.getFirstChild();
tupple = new ArrayList();
}
else if (currentNode.getNodeType() == Node.CAST)
{
if (currentExpr == null && tupple.size() > 1)
{
// Start from PrimaryExpression and invoke on that
currentExpr = new PrimaryExpression(symtbl, tupple.subList(0, tupple.size()-1));
PrimaryExpression primExpr = (PrimaryExpression)currentExpr;
if (primExpr.tuples.size() == 1)
{
Symbol sym = symtbl.getSymbol(primExpr.getId());
if (sym != null)
{
if (sym.getType() == Symbol.PARAMETER)
{
// Parameter symbol registered for this identifier so use ParameterExpression
currentExpr = new ParameterExpression(symtbl, primExpr.getId(), -1);
}
else if (sym.getType() == Symbol.VARIABLE)
{
// Variable symbol registered for this identifier so use VariableExpression
currentExpr = new VariableExpression(symtbl, primExpr.getId());
}
}
}
}
String className = (String)tupple.get(tupple.size()-1);
currentExpr = new CastExpression(symtbl, currentExpr, className);
currentNode = currentNode.getFirstChild();
tupple = new ArrayList();
}
else
{
// Part of identifier chain
currentNode = currentNode.getFirstChild();
}
}
if (currentExpr != null && tupple.size() > 0)
{
// We have a trailing identifier expression
// e.g "((B)a).c" where we have a CastExpression and trailing "c"
currentExpr = new PrimaryExpression(symtbl, currentExpr, tupple);
}
if (currentExpr == null)
{
// Find type of first of tupples
String first = (String)tupple.get(0);
Symbol firstSym = symtbl.getSymbol(first);
if (firstSym != null)
{
if (firstSym.getType() == Symbol.PARAMETER)
{
ParameterExpression paramExpr = new ParameterExpression(symtbl, first, -1);
if (tupple.size() > 1)
{
currentExpr = new PrimaryExpression(symtbl, paramExpr, tupple.subList(1, tupple.size()));
}
else
{
currentExpr = paramExpr;
}
}
else if (firstSym.getType() == Symbol.VARIABLE)
{
VariableExpression varExpr = new VariableExpression(symtbl, first);
if (tupple.size() > 1)
{
currentExpr = new PrimaryExpression(symtbl, varExpr, tupple.subList(1, tupple.size()));
}
else
{
currentExpr = varExpr;
}
}
else
{
currentExpr = new PrimaryExpression(symtbl, tupple);
}
}
else
{
currentExpr = new PrimaryExpression(symtbl, tupple);
}
}
return currentExpr;
}
else if (node.getNodeType() == Node.PARAMETER)
{
// "{paramExpr}", "{paramExpr}.invoke(...)", "{paramExpr}.invoke(...).invoke(...)"
Object val = node.getNodeValue();
Expression currentExpr = null;
if (val instanceof Integer)
{
// Positional parameter TODO Store as Integer to avoid confusion
currentExpr = new ParameterExpression(symtbl, "" + node.getNodeValue(),
((ParameterNode)node).getPosition());
}
else
{
// Named parameter
currentExpr = new ParameterExpression(symtbl, (String)node.getNodeValue(),
((ParameterNode)node).getPosition());
}
Node childNode = node.getFirstChild();
while (childNode != null)
{
if (childNode.getNodeType() == Node.INVOKE)
{
String methodName = (String)childNode.getNodeValue();
List parameterExprs = getExpressionsForPropertiesOfNode(childNode);
currentExpr = new InvokeExpression(symtbl, currentExpr, methodName, parameterExprs);
}
else
{
throw new QueryCompilerSyntaxException("Dont support compilation of " + node);
}
childNode = childNode.getFirstChild();
}
return currentExpr;
}
else if (node.getNodeType() == Node.INVOKE)
{
Node currentNode = node;
List tupple = new ArrayList();
Expression currentExpr = null;
while (currentNode != null)
{
tupple.add(currentNode.getNodeValue());
if (currentNode.getNodeType() == Node.INVOKE)
{
String methodName = (String)tupple.get(tupple.size()-1);
List parameterExprs = getExpressionsForPropertiesOfNode(currentNode);
currentExpr = new InvokeExpression(symtbl, currentExpr, methodName, parameterExprs);
currentNode = currentNode.getFirstChild();
if (currentNode != null)
{
// Continue on along the chain
tupple = new ArrayList();
tupple.add(currentExpr); // Start from this expression
}
}
else
{
// TODO What node type is this that comes after an INVOKE?
currentNode = currentNode.getFirstChild();
}
}
return currentExpr;
}
else if (node.getNodeType() == Node.CREATOR)
{
Node currentNode = node.getFirstChild();
List tupple = new ArrayList();
boolean method = false;
while (currentNode != null)
{
tupple.add(currentNode.getNodeValue());
if (currentNode.getNodeType() == Node.INVOKE)
{
method = true;
break;
}
currentNode = currentNode.getFirstChild();
}
List parameterExprs = null;
if (method)
{
parameterExprs = getExpressionsForPropertiesOfNode(currentNode);
}
else
{
parameterExprs = new ArrayList();
}
return new CreatorExpression(symtbl, tupple, parameterExprs);
}
else if (node.getNodeType() == Node.LITERAL)
{
Node currentNode = node;
List tupple = new ArrayList();
Expression currentExpr = null;
while (currentNode != null)
{
tupple.add(currentNode.getNodeValue());
if (currentNode.getNodeType() == Node.INVOKE)
{
if (currentExpr == null && tupple.size() > 1)
{
// Start from Literal and invoke on that
currentExpr = new Literal(node.getNodeValue());
}
String methodName = (String)tupple.get(tupple.size()-1);
List parameterExprs = getExpressionsForPropertiesOfNode(currentNode);
currentExpr = new InvokeExpression(symtbl, currentExpr, methodName, parameterExprs);
currentNode = currentNode.getFirstChild();
tupple = new ArrayList();
}
else
{
currentNode = currentNode.getFirstChild();
}
}
if (currentExpr == null)
{
currentExpr = new Literal(node.getNodeValue());
}
return currentExpr;
}
else if (node.getNodeType() == Node.ARRAY)
{
Node currentNode = node;
List<Node> arrayElements = (List<Node>)node.getNodeValue();
// Check if this is an array literal
boolean literal = true;
Class type = null;
Iterator<Node> iter = arrayElements.iterator();
while (iter.hasNext())
{
Node element = iter.next();
if (type == null)
{
type = element.getNodeValue().getClass();
}
else if (type != element.getNodeValue().getClass())
{
// TODO Allow for mixed-mode arrays e.g "(1,3,4,this.longField)"
throw new QueryCompilerSyntaxException("Array elements are of inconsistent types in " + node);
}
if (element.getNodeType() == Node.IDENTIFIER)
{
literal = false;
break;
}
}
Expression currentExpr = null;
if (literal)
{
Object array = Array.newInstance(type, arrayElements.size());
iter = arrayElements.iterator();
int index = 0;
while (iter.hasNext())
{
Node element = iter.next();
Array.set(array, index++, element.getNodeValue());
}
currentExpr = new Literal(array);
}
else
{
// TODO Handle ArrayExpression
throw new NucleusUserException("Compilation of an array of expressions is not yet supported");
}
currentNode = currentNode.getFirstChild();
List tupple = new ArrayList();
while (currentNode != null)
{
tupple.add(currentNode.getNodeValue());
if (currentNode.getNodeType() == Node.INVOKE)
{
if (currentExpr == null && tupple.size() > 1)
{
// Start from Literal and invoke on that
currentExpr = new Literal(node.getNodeValue());
}
String methodName = (String)tupple.get(tupple.size()-1);
List parameterExprs = getExpressionsForPropertiesOfNode(currentNode);
currentExpr = new InvokeExpression(symtbl, currentExpr, methodName, parameterExprs);
currentNode = currentNode.getFirstChild();
tupple = new ArrayList();
}
else
{
currentNode = currentNode.getFirstChild();
}
}
return currentExpr;
}
else if (node.getNodeType() == Node.SUBQUERY)
{
List children = node.getChildNodes();
if (children.size() != 1)
{
throw new QueryCompilerSyntaxException("Invalid number of children for SUBQUERY node : " + node);
}
Node varNode = (Node)children.get(0);
VariableExpression subqueryExpr = new VariableExpression(symtbl, varNode.getNodeId());
Expression currentExpr = new SubqueryExpression((String)node.getNodeValue(), subqueryExpr);
return currentExpr;
}
else
{