use of org.apache.commons.jexl2.parser.ASTIdentifier in project commons-jexl by apache.
the class Interpreter method visit.
@Override
protected Object visit(final ASTFunctionNode node, final Object data) {
final ASTIdentifier functionNode = (ASTIdentifier) node.jjtGetChild(0);
final String nsid = functionNode.getNamespace();
final Object namespace = (nsid != null) ? resolveNamespace(nsid, node) : context;
final ASTArguments argNode = (ASTArguments) node.jjtGetChild(1);
return call(node, namespace, functionNode, argNode);
}
use of org.apache.commons.jexl2.parser.ASTIdentifier in project commons-jexl by apache.
the class Interpreter method visit.
@Override
protected Object visit(final ASTReference node, final Object data) {
cancelCheck(node);
final int numChildren = node.jjtGetNumChildren();
final JexlNode parent = node.jjtGetParent();
// pass first piece of data in and loop through children
Object object = null;
JexlNode objectNode = null;
JexlNode ptyNode = null;
StringBuilder ant = null;
boolean antish = !(parent instanceof ASTReference);
int v = 1;
main: for (int c = 0; c < numChildren; c++) {
objectNode = node.jjtGetChild(c);
if (objectNode instanceof ASTMethodNode) {
antish = false;
if (object == null) {
// we may be performing a method call on an antish var
if (ant != null) {
final JexlNode child = objectNode.jjtGetChild(0);
if (child instanceof ASTIdentifierAccess) {
final int alen = ant.length();
ant.append('.');
ant.append(((ASTIdentifierAccess) child).getName());
object = context.get(ant.toString());
if (object != null) {
object = visit((ASTMethodNode) objectNode, object, context);
continue;
}
// remove method name from antish
ant.delete(alen, ant.length());
ptyNode = objectNode;
}
}
break;
}
} else if (objectNode instanceof ASTArrayAccess) {
antish = false;
if (object == null) {
ptyNode = objectNode;
break;
}
}
// attempt to evaluate the property within the object (visit(ASTIdentifierAccess node))
object = objectNode.jjtAccept(this, object);
cancelCheck(node);
if (object != null) {
// disallow mixing antish variable & bean with same root; avoid ambiguity
antish = false;
} else if (antish) {
// create first from first node
if (ant == null) {
// if we still have a null object, check for an antish variable
final JexlNode first = node.jjtGetChild(0);
if (!(first instanceof ASTIdentifier)) {
// not an identifier, not antish
ptyNode = objectNode;
break main;
}
final ASTIdentifier afirst = (ASTIdentifier) first;
ant = new StringBuilder(afirst.getName());
// *... and continue
if (!options.isAntish()) {
antish = false;
continue;
}
// skip the first node case since it was trialed in jjtAccept above and returned null
if (c == 0) {
continue;
}
}
// catch up to current node
for (; v <= c; ++v) {
final JexlNode child = node.jjtGetChild(v);
if (!(child instanceof ASTIdentifierAccess)) {
// not an identifier, not antish
ptyNode = objectNode;
break main;
}
final ASTIdentifierAccess achild = (ASTIdentifierAccess) child;
if (achild.isSafe() || achild.isExpression()) {
break main;
}
ant.append('.');
ant.append(achild.getName());
}
// solve antish
object = context.get(ant.toString());
} else if (c != numChildren - 1) {
// only the last one may be null
ptyNode = objectNode;
//
break;
}
}
// dealing with null
if (object == null) {
if (ptyNode != null) {
if (ptyNode.isSafeLhs(isSafe())) {
return null;
}
if (ant != null) {
final String aname = ant.toString();
final boolean defined = isVariableDefined(frame, block, aname);
return unsolvableVariable(node, aname, !defined);
}
return unsolvableProperty(node, stringifyProperty(ptyNode), ptyNode == objectNode, null);
}
if (antish) {
if (node.isSafeLhs(isSafe())) {
return null;
}
final String aname = ant != null ? ant.toString() : "?";
final boolean defined = isVariableDefined(frame, block, aname);
// defined but null; arg of a strict operator?
if (defined && !isStrictOperand(node)) {
return null;
}
return unsolvableVariable(node, aname, !defined);
}
}
return object;
}
use of org.apache.commons.jexl2.parser.ASTIdentifier in project commons-jexl by apache.
the class TemplateInterpreter method visit.
/**
* Interprets a function node.
* print() and include() must be decoded by this interpreter since delegating to the Uberspect
* may be sandboxing the interpreter itself making it unable to call the function.
* @param node the function node
* @param data the data
* @return the function evaluation result.
*/
@Override
protected Object visit(final ASTFunctionNode node, Object data) {
final int argc = node.jjtGetNumChildren();
if (argc == 2) {
final ASTIdentifier functionNode = (ASTIdentifier) node.jjtGetChild(0);
if ("jexl".equals(functionNode.getNamespace())) {
final String functionName = functionNode.getName();
final ASTArguments argNode = (ASTArguments) node.jjtGetChild(1);
if ("print".equals(functionName)) {
// evaluate the arguments
Object[] argv = visit(argNode, null);
if (argv != null && argv.length > 0 && argv[0] instanceof Number) {
print(((Number) argv[0]).intValue());
return null;
}
}
if ("include".equals(functionName)) {
// evaluate the arguments
Object[] argv = visit(argNode, null);
if (argv != null && argv.length > 0) {
if (argv[0] instanceof TemplateScript) {
TemplateScript script = (TemplateScript) argv[0];
if (argv.length > 1) {
argv = Arrays.copyOfRange(argv, 1, argv.length);
} else {
argv = null;
}
include(script, argv);
return null;
}
}
}
// fail safe
throw new JxltEngine.Exception(node.jexlInfo(), "no callable template function " + functionName, null);
}
}
return super.visit(node, data);
}
use of org.apache.commons.jexl2.parser.ASTIdentifier in project commons-jexl by apache.
the class Dumper method dump.
private void dump(final JexlNode node, final Object data) {
final int num = node.jjtGetNumChildren();
indent();
strb.append(node.getClass().getSimpleName());
if (node instanceof ASTIdentifier) {
strb.append("@");
strb.append(node.toString());
} else if (node instanceof ASTIdentifierAccess) {
strb.append("@");
strb.append(node.toString());
}
strb.append('(');
indent += 1;
for (int c = 0; c < num; ++c) {
final JexlNode child = node.jjtGetChild(c);
if (c > 0) {
strb.append(',');
}
strb.append('\n');
dump(child, data);
}
indent -= 1;
if (num > 0) {
strb.append('\n');
indent();
}
strb.append(')');
}
use of org.apache.commons.jexl2.parser.ASTIdentifier in project commons-jexl by apache.
the class Engine method getVariables.
/**
* Fills up the list of variables accessed by a node.
* @param script the owning script
* @param node the node
* @param collector the variable collector
*/
protected void getVariables(final ASTJexlScript script, final JexlNode node, final VarCollector collector) {
if (node instanceof ASTIdentifier) {
final JexlNode parent = node.jjtGetParent();
if (parent instanceof ASTMethodNode || parent instanceof ASTFunctionNode) {
// skip identifiers for methods and functions
collector.collect(null);
return;
}
final ASTIdentifier identifier = (ASTIdentifier) node;
final int symbol = identifier.getSymbol();
// symbols that are captured are considered "global" variables
if (symbol >= 0 && script != null && !script.isCapturedSymbol(symbol)) {
collector.collect(null);
} else {
// start collecting from identifier
collector.collect(identifier);
collector.add(identifier.getName());
}
} else if (node instanceof ASTIdentifierAccess) {
final JexlNode parent = node.jjtGetParent();
if (parent instanceof ASTMethodNode || parent instanceof ASTFunctionNode) {
// skip identifiers for methods and functions
collector.collect(null);
return;
}
// belt and suspender since an identifier should have been seen first
if (collector.isCollecting()) {
collector.add(((ASTIdentifierAccess) node).getName());
}
} else if (node instanceof ASTArrayAccess && collector.mode > 0) {
final int num = node.jjtGetNumChildren();
// collect only if array access is const and follows an identifier
boolean collecting = collector.isCollecting();
for (int i = 0; i < num; ++i) {
final JexlNode child = node.jjtGetChild(i);
if (collecting && child.isConstant()) {
// collect all constants or only string and number literals
final boolean collect = collector.mode > 1 || (child instanceof ASTStringLiteral || child instanceof ASTNumberLiteral);
if (collect) {
final String image = child.toString();
collector.add(image);
}
} else {
collecting = false;
collector.collect(null);
getVariables(script, child, collector);
collector.collect(null);
}
}
} else {
final int num = node.jjtGetNumChildren();
for (int i = 0; i < num; ++i) {
getVariables(script, node.jjtGetChild(i), collector);
}
collector.collect(null);
}
}
Aggregations