use of org.apache.commons.jexl3.parser.ASTReference in project commons-jexl by apache.
the class Interpreter method executeAssign.
/**
* Executes an assignment with an optional side-effect operator.
* @param node the node
* @param assignop the assignment operator or null if simply assignment
* @param data the data
* @return the left hand side
*/
protected Object executeAssign(final JexlNode node, final JexlOperator assignop, final Object data) {
// CSOFF: MethodLength
cancelCheck(node);
// left contains the reference to assign to
final JexlNode left = node.jjtGetChild(0);
ASTIdentifier var = null;
Object object = null;
int symbol = -1;
// check var decl with assign is ok
if (left instanceof ASTIdentifier) {
var = (ASTIdentifier) left;
symbol = var.getSymbol();
if (symbol >= 0 && options.isLexical()) {
if (var instanceof ASTVar) {
if (!defineVariable((ASTVar) var, block)) {
return redefinedVariable(var, var.getName());
}
} else if (options.isLexicalShade() && var.isShaded()) {
return undefinedVariable(var, var.getName());
}
}
}
boolean antish = options.isAntish();
// 0: determine initial object & property:
final int last = left.jjtGetNumChildren() - 1;
// right is the value expression to assign
Object right = node.jjtGetChild(1).jjtAccept(this, data);
// a (var?) v = ... expression
if (var != null) {
if (symbol >= 0) {
// check we are not assigning a symbol itself
if (last < 0) {
if (assignop != null) {
final Object self = getVariable(frame, block, var);
right = operators.tryAssignOverload(node, assignop, self, right);
if (right == JexlOperator.ASSIGN) {
return self;
}
}
frame.set(symbol, right);
// make the closure accessible to itself, ie capture the currently set variable after frame creation
if (right instanceof Closure) {
((Closure) right).setCaptured(symbol, right);
}
// 1
return right;
}
object = getVariable(frame, block, var);
// top level is a symbol, can not be an antish var
antish = false;
} else {
// check we are not assigning direct global
if (last < 0) {
if (assignop != null) {
final Object self = context.get(var.getName());
right = operators.tryAssignOverload(node, assignop, self, right);
if (right == JexlOperator.ASSIGN) {
return self;
}
}
setContextVariable(node, var.getName(), right);
// 2
return right;
}
object = context.get(var.getName());
// top level accesses object, can not be an antish var
if (object != null) {
antish = false;
}
}
} else if (!(left instanceof ASTReference)) {
throw new JexlException(left, "illegal assignment form 0");
}
// 1: follow children till penultimate, resolve dot/array
JexlNode objectNode = null;
StringBuilder ant = null;
int v = 1;
// start at 1 if symbol
main: for (int c = symbol >= 0 ? 1 : 0; c < last; ++c) {
objectNode = left.jjtGetChild(c);
object = objectNode.jjtAccept(this, object);
if (object != null) {
// disallow mixing antish variable & bean with same root; avoid ambiguity
antish = false;
} else if (antish) {
// initialize if first time
if (ant == null) {
final JexlNode first = left.jjtGetChild(0);
final ASTIdentifier firstId = first instanceof ASTIdentifier ? (ASTIdentifier) first : null;
if ((firstId == null) || (firstId.getSymbol() >= 0)) {
// ant remains null, object is null, stop solving
antish = false;
break main;
}
ant = new StringBuilder(firstId.getName());
}
// catch up to current child
for (; v <= c; ++v) {
final JexlNode child = left.jjtGetChild(v);
final ASTIdentifierAccess aid = child instanceof ASTIdentifierAccess ? (ASTIdentifierAccess) child : null;
// remain antish only if unsafe navigation
if ((aid == null) || aid.isSafe() || aid.isExpression()) {
antish = false;
break main;
}
ant.append('.');
ant.append(aid.getName());
}
// solve antish
object = context.get(ant.toString());
} else {
throw new JexlException(objectNode, "illegal assignment form");
}
}
// 2: last objectNode will perform assignement in all cases
JexlNode propertyNode = left.jjtGetChild(last);
final ASTIdentifierAccess propertyId = propertyNode instanceof ASTIdentifierAccess ? (ASTIdentifierAccess) propertyNode : null;
final Object property;
if (propertyId != null) {
// deal with creating/assignining antish variable
if (antish && ant != null && object == null && !propertyId.isSafe() && !propertyId.isExpression()) {
if (last > 0) {
ant.append('.');
}
ant.append(propertyId.getName());
if (assignop != null) {
final Object self = context.get(ant.toString());
right = operators.tryAssignOverload(node, assignop, self, right);
if (right == JexlOperator.ASSIGN) {
return self;
}
}
setContextVariable(propertyNode, ant.toString(), right);
// 3
return right;
}
// property of an object ?
property = evalIdentifier(propertyId);
} else if (propertyNode instanceof ASTArrayAccess) {
// can have multiple nodes - either an expression, integer literal or reference
final int numChildren = propertyNode.jjtGetNumChildren() - 1;
for (int i = 0; i < numChildren; i++) {
final JexlNode nindex = propertyNode.jjtGetChild(i);
final Object index = nindex.jjtAccept(this, null);
object = getAttribute(object, index, nindex);
}
propertyNode = propertyNode.jjtGetChild(numChildren);
property = propertyNode.jjtAccept(this, null);
} else {
throw new JexlException(objectNode, "illegal assignment form");
}
// we can not *have* a null object though.
if (object == null) {
// no object, we fail
return unsolvableProperty(objectNode, "<null>.<?>", true, null);
}
// 3: one before last, assign
if (assignop != null) {
final Object self = getAttribute(object, property, propertyNode);
right = operators.tryAssignOverload(node, assignop, self, right);
if (right == JexlOperator.ASSIGN) {
return self;
}
}
setAttribute(object, property, right, propertyNode);
// 4
return right;
}
use of org.apache.commons.jexl3.parser.ASTReference in project datawave by NationalSecurityAgency.
the class PruneLessSelectiveFieldsVisitor method visit.
@Override
public Object visit(ASTAndNode node, Object data) {
JexlNode mostSelectiveChild = null;
Double maxSelectivity = Double.valueOf("-1");
boolean foundSelectivity = false;
ASTAndNode newNode = new ASTAndNode(ParserTreeConstants.JJTANDNODE);
newNode.image = node.image;
newNode.jjtSetParent(node.jjtGetParent());
for (int i = 0; i < node.jjtGetNumChildren(); i++) {
JexlNode child = (JexlNode) node.jjtGetChild(i).jjtAccept(this, null);
Double selectivity;
if (child instanceof ASTOrNode || child instanceof ASTReference || child instanceof ASTReferenceExpression) {
// Check for the selectivity of the OR
selectivity = getOrSelectivity(child);
} else {
selectivity = JexlASTHelper.getNodeSelectivity(child, config, stats);
}
// Don't want to fail if there's an issue with one child...
if (!selectivity.equals(IndexStatsClient.DEFAULT_VALUE) && selectivity > maxSelectivity) {
foundSelectivity = true;
// Hold on to the most selective child
mostSelectiveChild = RebuildingVisitor.copy(child);
maxSelectivity = selectivity;
}
}
if (!foundSelectivity || null == mostSelectiveChild) {
// Something went wrong, so just return the node we started with
return RebuildingVisitor.copy(node);
} else {
newNode.jjtAddChild(mostSelectiveChild, newNode.jjtGetNumChildren());
}
return newNode;
}
use of org.apache.commons.jexl3.parser.ASTReference in project datawave by NationalSecurityAgency.
the class PushdownLargeFieldedListsVisitor method assignNodeByField.
protected void assignNodeByField(JexlNode origNode, JexlNode subNode, Multimap<String, JexlNode> eqNodes, Multimap<String, JexlNode> rangeNodes, List<JexlNode> otherNodes) {
QueryPropertyMarker.Instance instance = QueryPropertyMarker.findInstance(subNode);
if (subNode instanceof ASTEQNode) {
String identifier = JexlASTHelper.getIdentifier(subNode, false);
if (identifier != null) {
eqNodes.put(JexlASTHelper.getIdentifier(subNode, false), origNode);
} else {
otherNodes.add(origNode);
}
} else if (instance.isType(ExceededValueThresholdMarkerJexlNode.class)) {
assignNodeByField(origNode, instance.getSource(), eqNodes, rangeNodes, otherNodes);
} else if (instance.isType(BoundedRange.class)) {
LiteralRange range = JexlASTHelper.findRange().getRange(subNode);
rangeNodes.put(JexlASTHelper.rebuildIdentifier(range.getFieldName()), origNode);
} else if ((subNode.jjtGetNumChildren() == 1) && (subNode instanceof ASTReferenceExpression || subNode instanceof ASTReference || subNode instanceof ASTAndNode)) {
assignNodeByField(origNode, subNode.jjtGetChild(0), eqNodes, rangeNodes, otherNodes);
} else {
otherNodes.add(origNode);
}
}
use of org.apache.commons.jexl3.parser.ASTReference in project datawave by NationalSecurityAgency.
the class JexlStringBuildingVisitor method visit.
@Override
public Object visit(ASTMethodNode node, Object data) {
StringBuilder sb = (StringBuilder) data;
StringBuilder methodStringBuilder = new StringBuilder();
StringBuilder argumentStringBuilder = new StringBuilder();
int kidCount = node.jjtGetNumChildren();
for (int i = 0; i < kidCount; i++) {
if (i == 0) {
JexlNode methodNode = node.jjtGetChild(i);
methodStringBuilder.append(".");
if (allowedMethods.contains(methodNode.image) == false) {
QueryException qe = new QueryException(DatawaveErrorCode.METHOD_COMPOSITION_ERROR, MessageFormat.format("{0}", methodNode.image));
throw new DatawaveFatalQueryException(qe);
}
methodStringBuilder.append(methodNode.image);
// parens are open. don't forget to close
methodStringBuilder.append("(");
} else {
// adding any method arguments
JexlNode argumentNode = node.jjtGetChild(i);
if (argumentNode instanceof ASTReference) {
// a method may have an argument that is another method. In this case, descend the visit tree for it
if (JexlASTHelper.HasMethodVisitor.hasMethod(argumentNode)) {
this.visit((ASTReference) argumentNode, argumentStringBuilder);
} else {
for (int j = 0; j < argumentNode.jjtGetNumChildren(); j++) {
JexlNode argKid = argumentNode.jjtGetChild(j);
if (argKid instanceof ASTFunctionNode) {
this.visit((ASTFunctionNode) argKid, argumentStringBuilder);
} else {
if (argumentStringBuilder.length() > 0) {
argumentStringBuilder.append(",");
}
if (argKid instanceof ASTStringLiteral) {
argumentStringBuilder.append("'");
}
argumentStringBuilder.append(argKid.image);
if (argKid instanceof ASTStringLiteral) {
argumentStringBuilder.append("'");
}
}
}
}
} else if (argumentNode instanceof ASTNumberLiteral) {
if (argumentStringBuilder.length() > 0) {
argumentStringBuilder.append(",");
}
argumentStringBuilder.append(argumentNode.image);
}
}
}
methodStringBuilder.append(argumentStringBuilder);
// close parens in method
methodStringBuilder.append(")");
sb.append(methodStringBuilder);
return sb;
}
use of org.apache.commons.jexl3.parser.ASTReference in project datawave by NationalSecurityAgency.
the class JexlStringBuildingVisitor method visit.
public Object visit(ASTStringLiteral node, Object data) {
StringBuilder sb = (StringBuilder) data;
String literal = node.image;
JexlNode parent = node;
do {
parent = parent.jjtGetParent();
} while (parent instanceof ASTReference);
// visitor can be correctly parsed back into the current query tree.
if (!(parent instanceof ASTERNode || parent instanceof ASTNRNode))
literal = literal.replace(JexlASTHelper.SINGLE_BACKSLASH, JexlASTHelper.DOUBLE_BACKSLASH);
int index = literal.indexOf(STRING_QUOTE);
if (-1 != index) {
// Slightly larger buffer
int begin = 0;
StringBuilder builder = new StringBuilder(literal.length() + 10);
// Find every single quote and escape it
while (-1 != index) {
builder.append(literal.substring(begin, index));
builder.append(BACKSLASH).append(STRING_QUOTE);
begin = index + 1;
index = literal.indexOf(STRING_QUOTE, begin);
}
// Tack on the end of the literal
builder.append(literal.substring(begin));
// Set the new version on the literal
literal = builder.toString();
}
sb.append(STRING_QUOTE).append(literal).append(STRING_QUOTE);
node.childrenAccept(this, sb);
return sb;
}
Aggregations