use of org.mvel2.ast.ASTNode in project mvel by mvel.
the class MVELInterpretedRuntime method parseAndExecuteInterpreted.
/**
* Main interpreter loop.
*
* @return value
*/
private Object parseAndExecuteInterpreted() {
ASTNode tk = null;
int operator;
lastWasIdentifier = false;
try {
while ((tk = nextToken()) != null) {
holdOverRegister = null;
if (lastWasIdentifier && lastNode.isDiscard()) {
stk.discard();
}
/**
* If we are at the beginning of a statement, then we immediately push the first token
* onto the stack.
*/
if (stk.isEmpty()) {
if ((tk.fields & ASTNode.STACKLANG) != 0) {
stk.push(tk.getReducedValue(stk, ctx, variableFactory));
Object o = stk.peek();
if (o instanceof Integer) {
arithmeticFunctionReduction((Integer) o);
}
} else {
stk.push(tk.getReducedValue(ctx, ctx, variableFactory));
}
/**
* If this is a substatement, we need to move the result into the d-stack to preserve
* proper execution order.
*/
if (tk instanceof Substatement && (tk = nextToken()) != null) {
if (isArithmeticOperator(operator = tk.getOperator())) {
stk.push(nextToken().getReducedValue(ctx, ctx, variableFactory), operator);
if (procBooleanOperator(arithmeticFunctionReduction(operator)) == -1)
return stk.peek();
else
continue;
}
} else {
continue;
}
}
if (variableFactory.tiltFlag()) {
return stk.pop();
}
switch(procBooleanOperator(operator = tk.getOperator())) {
case RETURN:
variableFactory.setTiltFlag(true);
return stk.pop();
case OP_TERMINATE:
return stk.peek();
case OP_RESET_FRAME:
continue;
case OP_OVERFLOW:
if (!tk.isOperator()) {
if (!(stk.peek() instanceof Class)) {
throw new CompileException("unexpected token or unknown identifier:" + tk.getName(), expr, st);
}
variableFactory.createVariable(tk.getName(), null, (Class) stk.peek());
}
continue;
}
stk.push(nextToken().getReducedValue(ctx, ctx, variableFactory), operator);
switch((operator = arithmeticFunctionReduction(operator))) {
case OP_TERMINATE:
return stk.peek();
case OP_RESET_FRAME:
continue;
}
if (procBooleanOperator(operator) == OP_TERMINATE)
return stk.peek();
}
if (holdOverRegister != null) {
return holdOverRegister;
}
} catch (CompileException e) {
throw ErrorUtil.rewriteIfNeeded(e, expr, start);
} catch (NullPointerException e) {
if (tk != null && tk.isOperator()) {
CompileException ce = new CompileException("incomplete statement: " + tk.getName() + " (possible use of reserved keyword as identifier: " + tk.getName() + ")", expr, st, e);
ce.setExpr(expr);
ce.setLineNumber(line);
ce.setCursor(cursor);
throw ce;
} else {
throw e;
}
}
return stk.peek();
}
use of org.mvel2.ast.ASTNode in project mvel by mvel.
the class CoreConfidenceTests method testInterceptors.
public void testInterceptors() {
Interceptor testInterceptor = new Interceptor() {
public int doBefore(ASTNode node, VariableResolverFactory factory) {
System.out.println("BEFORE Node: " + node.getName());
return 0;
}
public int doAfter(Object val, ASTNode node, VariableResolverFactory factory) {
System.out.println("AFTER Node: " + node.getName());
return 0;
}
};
Map<String, Interceptor> interceptors = new HashMap<String, Interceptor>();
interceptors.put("test", testInterceptor);
executeExpression(compileExpression("@test System.out.println('MIDDLE');", null, interceptors));
}
use of org.mvel2.ast.ASTNode in project mvel by mvel.
the class AbstractParser method createPropertyToken.
/**
* Generate a property token
*
* @param st the start offset
* @param end the end offset
* @return an ast node
*/
private ASTNode createPropertyToken(int st, int end) {
String tmp;
if (isPropertyOnly(expr, st, end)) {
if (pCtx != null && pCtx.hasImports()) {
int find;
if ((find = findFirst('.', st, end - st, expr)) != -1) {
String iStr = new String(expr, st, find - st);
if (pCtx.hasImport(iStr)) {
lastWasIdentifier = true;
return lastNode = new LiteralDeepPropertyNode(expr, find + 1, end - find - 1, fields, pCtx.getImport(iStr), pCtx);
}
} else {
if (pCtx.hasImport(tmp = new String(expr, st, cursor - st))) {
lastWasIdentifier = true;
return lastNode = new LiteralNode(pCtx.getStaticOrClassImport(tmp), pCtx);
}
}
}
if (LITERALS.containsKey(tmp = new String(expr, st, end - st))) {
lastWasIdentifier = true;
return lastNode = new LiteralNode(LITERALS.get(tmp), pCtx);
} else if (OPERATORS.containsKey(tmp)) {
lastWasIdentifier = false;
return lastNode = new OperatorNode(OPERATORS.get(tmp), expr, st, pCtx);
} else if (lastWasIdentifier) {
return procTypedNode(true);
}
}
if (pCtx != null && isArrayType(expr, st, end)) {
if (pCtx.hasImport(new String(expr, st, cursor - st - 2))) {
lastWasIdentifier = true;
TypeDescriptor typeDescriptor = new TypeDescriptor(expr, st, cursor - st, fields);
try {
return lastNode = new LiteralNode(typeDescriptor.getClassReference(pCtx), pCtx);
} catch (ClassNotFoundException e) {
throw new CompileException("could not resolve class: " + typeDescriptor.getClassName(), expr, st);
}
}
}
lastWasIdentifier = true;
return lastNode = new ASTNode(expr, trimRight(st), trimLeft(end) - st, fields, pCtx);
}
use of org.mvel2.ast.ASTNode in project mvel by mvel.
the class AbstractParser method arithmeticFunctionReduction.
/**
* Reduce the current operations on the stack.
*
* @param operator the operator
* @return a stack control code
*/
protected int arithmeticFunctionReduction(int operator) {
ASTNode tk;
int operator2;
/**
* If the next token is an operator, we check to see if it has a higher
* precdence.
*/
if ((tk = nextToken()) != null) {
if (isArithmeticOperator(operator2 = tk.getOperator()) && PTABLE[operator2] > PTABLE[operator]) {
stk.xswap();
/**
* The current arith. operator is of higher precedence the last.
*/
tk = nextToken();
/**
* Check to see if we're compiling or executing interpretively. If we're compiling, we really
* need to stop if this is not a literal.
*/
if (compileMode && !tk.isLiteral()) {
splitAccumulator.push(tk, new OperatorNode(operator2, expr, st, pCtx));
return OP_OVERFLOW;
}
dStack.push(operator = operator2, tk.getReducedValue(ctx, ctx, variableFactory));
while (true) {
ASTNode previousToken = tk;
// look ahead again
if ((tk = nextToken()) != null && (operator2 = tk.getOperator()) != -1 && operator2 != END_OF_STMT && PTABLE[operator2] > PTABLE[operator]) {
if (dStack.isReduceable()) {
stk.copyx2(dStack);
}
/**
* This operator is of higher precedence, or the same level precedence. push to the RHS.
*/
ASTNode nextToken = nextToken();
if (compileMode && !nextToken.isLiteral()) {
splitAccumulator.push(nextToken, new OperatorNode(operator2, expr, st, pCtx));
return OP_OVERFLOW;
}
dStack.push(operator = operator2, nextToken.getReducedValue(ctx, ctx, variableFactory));
continue;
} else if (tk != null && operator2 != -1 && operator2 != END_OF_STMT) {
if (PTABLE[operator2] == PTABLE[operator]) {
if (!dStack.isEmpty())
dreduce();
else {
while (stk.isReduceable()) {
stk.xswap_op();
}
}
/**
* This operator is of the same level precedence. push to the RHS.
*/
dStack.push(operator = operator2, nextToken().getReducedValue(ctx, ctx, variableFactory));
continue;
} else {
/**
* The operator doesn't have higher precedence. Therfore reduce the LHS.
*/
while (dStack.size() > 1) {
dreduce();
}
operator = tk.getOperator();
// Reduce the lesser or equal precedence operations.
while (stk.size() != 1 && stk.peek2() instanceof Integer && ((operator2 = (Integer) stk.peek2()) < PTABLE.length) && PTABLE[operator2] >= PTABLE[operator]) {
stk.xswap_op();
}
}
} else {
if (dStack.size() > 1) {
dreduce();
}
if (stk.isReduceable())
stk.xswap();
break;
}
if ((tk = nextToken()) != null) {
switch(operator) {
case AND:
{
if (!(stk.peekBoolean()))
return OP_TERMINATE;
else {
splitAccumulator.add(tk);
return AND;
}
}
case OR:
{
if ((stk.peekBoolean()))
return OP_TERMINATE;
else {
splitAccumulator.add(tk);
return OR;
}
}
default:
if (compileMode && !tk.isLiteral()) {
stk.push(operator, tk);
return OP_NOT_LITERAL;
}
stk.push(operator, tk.getReducedValue(ctx, ctx, variableFactory));
}
}
}
} else if (!tk.isOperator()) {
throw new CompileException("unexpected token: " + tk.getName(), expr, st);
} else {
reduce();
splitAccumulator.push(tk);
}
}
// keep XSWAPing and reducing, until there is nothing left.
if (stk.isReduceable()) {
while (true) {
reduce();
if (stk.isReduceable()) {
stk.xswap();
} else {
break;
}
}
}
return OP_RESET_FRAME;
}
use of org.mvel2.ast.ASTNode in project mvel by mvel.
the class ExpressionCompiler method verify.
protected ASTNode verify(ParserContext pCtx, ASTNode tk) {
if (tk.isOperator() && (tk.getOperator().equals(Operator.AND) || tk.getOperator().equals(Operator.OR))) {
secondPassOptimization = true;
}
if (tk.isDiscard() || tk.isOperator()) {
return tk;
} else if (tk.isLiteral()) {
/**
* Convert literal values from the default ASTNode to the more-efficient LiteralNode.
*/
if ((fields & COMPILE_IMMEDIATE) != 0 && tk.getClass() == ASTNode.class) {
return new LiteralNode(tk.getLiteralValue(), pCtx);
} else {
return tk;
}
}
if (verifying) {
if (tk.isIdentifier()) {
PropertyVerifier propVerifier = new PropertyVerifier(expr, tk.getStart(), tk.getOffset(), pCtx);
if (tk instanceof Union) {
propVerifier.setCtx(((Union) tk).getLeftEgressType());
tk.setEgressType(returnType = propVerifier.analyze());
} else {
tk.setEgressType(returnType = propVerifier.analyze());
if (propVerifier.isFqcn()) {
tk.setAsFQCNReference();
}
if (propVerifier.isClassLiteral()) {
return new LiteralNode(returnType, pCtx);
}
if (propVerifier.isInput()) {
pCtx.addInput(tk.getAbsoluteName(), propVerifier.isDeepProperty() ? Object.class : returnType);
}
if (!propVerifier.isMethodCall() && !returnType.isEnum() && !pCtx.isOptimizerNotified() && pCtx.isStrongTyping() && !pCtx.isVariableVisible(tk.getAbsoluteName()) && !tk.isFQCN()) {
throw new CompileException("no such identifier: " + tk.getAbsoluteName(), expr, tk.getStart());
}
}
} else if (tk.isAssignment()) {
Assignment a = (Assignment) tk;
if (a.getAssignmentVar() != null) {
// pCtx.makeVisible(a.getAssignmentVar());
PropertyVerifier propVerifier = new PropertyVerifier(a.getAssignmentVar(), pCtx);
tk.setEgressType(returnType = propVerifier.analyze());
if (!a.isNewDeclaration() && propVerifier.isResolvedExternally()) {
pCtx.addInput(tk.getAbsoluteName(), returnType);
}
ExecutableStatement c = (ExecutableStatement) subCompileExpression(expr, tk.getStart(), tk.getOffset(), pCtx);
if (pCtx.isStrictTypeEnforcement()) {
/**
* If we're using strict type enforcement, we need to see if this coercion can be done now,
* or fail epicly.
*/
if (!returnType.isAssignableFrom(c.getKnownEgressType()) && c.isLiteralOnly()) {
if (canConvert(c.getKnownEgressType(), returnType)) {
/**
* We convert the literal to the proper type.
*/
try {
// Don't convert to a literal for DeepOperativeAssignmentNode. Coercion will be done by BinaryOperation
if (!(a instanceof DeepOperativeAssignmentNode)) {
a.setValueStatement(new ExecutableLiteral(convert(c.getValue(null, null), returnType)));
}
return tk;
} catch (Exception e) {
// fall through.
}
} else if (returnType.isPrimitive() && unboxPrimitive(c.getKnownEgressType()).equals(returnType)) {
/**
* We ignore boxed primitive cases, since MVEL does not recognize primitives.
*/
return tk;
}
throw new CompileException("cannot assign type " + c.getKnownEgressType().getName() + " to " + returnType.getName(), expr, st);
}
}
}
} else if (tk instanceof NewObjectNode) {
// this is a bit of a hack for now.
NewObjectNode n = (NewObjectNode) tk;
List<char[]> parms = ParseTools.parseMethodOrConstructor(tk.getNameAsArray());
if (parms != null) {
for (char[] p : parms) {
MVEL.analyze(p, pCtx);
}
}
}
returnType = tk.getEgressType();
}
if (!tk.isLiteral() && tk.getClass() == ASTNode.class && (tk.getFields() & ASTNode.ARRAY_TYPE_LITERAL) == 0) {
if (pCtx.isStrongTyping())
tk.strongTyping();
tk.storePctx();
tk.storeInLiteralRegister(pCtx);
}
return tk;
}
Aggregations