use of org.mvel2.ast.ASTNode in project mvel by mikebrock.
the class MVELRuntime method execute.
/**
* Main interpreter.
*
* @param debugger Run in debug mode
* @param expression The compiled expression object
* @param ctx The root context object
* @param variableFactory The variable factory to be injected
* @return The resultant value
* @see org.mvel2.MVEL
*/
public static Object execute(boolean debugger, final CompiledExpression expression, final Object ctx, VariableResolverFactory variableFactory) {
Object v1, v2;
ExecutionStack stk = new ExecutionStack();
variableFactory.setTiltFlag(false);
ASTNode tk = expression.getFirstNode();
Integer operator;
if (tk == null)
return null;
try {
do {
if (tk.fields == -1) {
/**
* This may seem silly and redundant, however, when an MVEL script recurses into a block
* or substatement, a new runtime loop is entered. Since the debugger state is not
* passed through the AST, it is not possible to forward the state directly. So when we
* encounter a debugging symbol, we check the thread local to see if there is are registered
* breakpoints. If we find them, we assume that we are debugging.
*
* The consequence of this of course, is that it's not ideal to compileShared expressions with
* debugging symbols which you plan to use in a production enviroment.
*/
if (debugger || (debugger = hasDebuggerContext())) {
try {
debuggerContext.get().checkBreak((LineLabel) tk, variableFactory, expression);
} catch (NullPointerException e) {
// do nothing for now. this isn't as calus as it seems.
}
}
continue;
} else if (stk.isEmpty()) {
stk.push(tk.getReducedValueAccelerated(ctx, ctx, variableFactory));
}
if (variableFactory.tiltFlag()) {
return stk.pop();
}
switch(operator = tk.getOperator()) {
case RETURN:
variableFactory.setTiltFlag(true);
return stk.pop();
case NOOP:
continue;
case TERNARY:
if (!stk.popBoolean()) {
//noinspection StatementWithEmptyBody
while (tk.nextASTNode != null && !(tk = tk.nextASTNode).isOperator(TERNARY_ELSE)) ;
}
stk.clear();
continue;
case TERNARY_ELSE:
return stk.pop();
case END_OF_STMT:
/**
* If the program doesn't end here then we wipe anything off the stack that remains.
* Althought it may seem like intuitive stack optimizations could be leveraged by
* leaving hanging values on the stack, trust me it's not a good idea.
*/
if (tk.nextASTNode != null) {
stk.clear();
}
continue;
}
stk.push(tk.nextASTNode.getReducedValueAccelerated(ctx, ctx, variableFactory), operator);
try {
while (stk.isReduceable()) {
if ((Integer) stk.peek() == CHOR) {
stk.pop();
v1 = stk.pop();
v2 = stk.pop();
if (!isEmpty(v2) || !isEmpty(v1)) {
stk.clear();
stk.push(!isEmpty(v2) ? v2 : v1);
} else
stk.push(null);
} else {
stk.op();
}
}
} catch (ClassCastException e) {
throw new CompileException("syntax error or incomptable types", new char[0], 0, e);
} catch (CompileException e) {
throw e;
} catch (Exception e) {
throw new CompileException("failed to compileShared sub expression", new char[0], 0, e);
}
} while ((tk = tk.nextASTNode) != null);
return stk.peek();
} catch (NullPointerException e) {
if (tk != null && tk.isOperator() && tk.nextASTNode != null) {
throw new CompileException("incomplete statement: " + tk.getName() + " (possible use of reserved keyword as identifier: " + tk.getName() + ")", tk.getExpr(), tk.getStart());
} else {
throw e;
}
}
}
use of org.mvel2.ast.ASTNode in project mvel by mikebrock.
the class AbstractParser method _captureBlock.
private ASTNode _captureBlock(ASTNode node, final char[] expr, boolean cond, int type) {
skipWhitespace();
int startCond = 0;
int endCond = 0;
int blockStart;
int blockEnd;
String name;
/**
* Functions are a special case we handle differently from the rest of block parsing
*/
switch(type) {
case FUNCTION:
{
int st = cursor;
captureToNextTokenJunction();
if (cursor == end) {
throw new CompileException("unexpected end of statement", expr, st);
}
/**
* Check to see if the name is legal.
*/
if (isReservedWord(name = createStringTrimmed(expr, st, cursor - st)) || isNotValidNameorLabel(name))
throw new CompileException("illegal function name or use of reserved word", expr, cursor);
if (pCtx == null)
pCtx = getParserContext();
FunctionParser parser = new FunctionParser(name, cursor, end - cursor, expr, fields, pCtx, splitAccumulator);
Function function = parser.parse();
cursor = parser.getCursor();
return lastNode = function;
}
case PROTO:
if (ProtoParser.isUnresolvedWaiting()) {
if (pCtx == null)
pCtx = getParserContext();
ProtoParser.checkForPossibleUnresolvedViolations(expr, cursor, pCtx);
}
int st = cursor;
captureToNextTokenJunction();
if (isReservedWord(name = createStringTrimmed(expr, st, cursor - st)) || isNotValidNameorLabel(name))
throw new CompileException("illegal prototype name or use of reserved word", expr, cursor);
if (expr[cursor = nextNonBlank()] != '{') {
throw new CompileException("expected '{' but found: " + expr[cursor], expr, cursor);
}
cursor = balancedCaptureWithLineAccounting(expr, st = cursor + 1, end, '{', pCtx);
if (pCtx == null)
pCtx = getParserContext();
ProtoParser parser = new ProtoParser(expr, st, cursor, name, pCtx, fields, splitAccumulator);
Proto proto = parser.parse();
if (pCtx == null)
pCtx = getParserContext();
pCtx.addImport(proto);
proto.setCursorPosition(st, cursor);
cursor = parser.getCursor();
ProtoParser.notifyForLateResolution(proto);
return lastNode = proto;
default:
if (cond) {
if (expr[cursor] != '(') {
throw new CompileException("expected '(' but encountered: " + expr[cursor], expr, cursor);
}
/**
* This block is an: IF, FOREACH or WHILE node.
*/
endCond = cursor = balancedCaptureWithLineAccounting(expr, startCond = cursor, end, '(', pCtx);
startCond++;
cursor++;
}
}
skipWhitespace();
if (cursor >= end) {
throw new CompileException("unexpected end of statement", expr, end);
} else if (expr[cursor] == '{') {
blockEnd = cursor = balancedCaptureWithLineAccounting(expr, blockStart = cursor, end, '{', pCtx);
} else {
blockStart = cursor - 1;
captureToEOSorEOL();
blockEnd = cursor + 1;
}
if (type == ASTNode.BLOCK_IF) {
IfNode ifNode = (IfNode) node;
if (node != null) {
if (!cond) {
return ifNode.setElseBlock(expr, st = trimRight(blockStart + 1), trimLeft(blockEnd) - st, pCtx);
} else {
return ifNode.setElseIf((IfNode) createBlockToken(startCond, endCond, trimRight(blockStart + 1), trimLeft(blockEnd), type));
}
} else {
return createBlockToken(startCond, endCond, blockStart + 1, blockEnd, type);
}
} else if (type == ASTNode.BLOCK_DO) {
cursor++;
skipWhitespace();
st = cursor;
captureToNextTokenJunction();
if ("while".equals(name = new String(expr, st, cursor - st))) {
skipWhitespace();
startCond = cursor + 1;
endCond = cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '(', pCtx);
return createBlockToken(startCond, endCond, trimRight(blockStart + 1), trimLeft(blockEnd), type);
} else if ("until".equals(name)) {
skipWhitespace();
startCond = cursor + 1;
endCond = cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '(', pCtx);
return createBlockToken(startCond, endCond, trimRight(blockStart + 1), trimLeft(blockEnd), ASTNode.BLOCK_DO_UNTIL);
} else {
throw new CompileException("expected 'while' or 'until' but encountered: " + name, expr, cursor);
}
} else // DON"T REMOVE THIS COMMENT!
// else if (isFlag(ASTNode.BLOCK_FOREACH) || isFlag(ASTNode.BLOCK_WITH)) {
{
return createBlockToken(startCond, endCond, trimRight(blockStart + 1), trimLeft(blockEnd), type);
}
}
use of org.mvel2.ast.ASTNode in project mvel by mikebrock.
the class CompiledExpression method toString.
public String toString() {
StringBuilder appender = new StringBuilder();
ASTNode node = firstNode;
while (node != null) {
appender.append(node.toString()).append(";\n");
node = node.nextASTNode;
}
return appender.toString();
}
use of org.mvel2.ast.ASTNode in project mvel by mikebrock.
the class MacroProcessorTest method testMacroSupportWithDebugging.
public void testMacroSupportWithDebugging() {
Map<String, Object> vars = new HashMap<String, Object>();
vars.put("foo", new Foo());
Map<String, Interceptor> interceptors = new HashMap<String, Interceptor>();
Map<String, Macro> macros = new HashMap<String, Macro>();
interceptors.put("Modify", new Interceptor() {
public int doBefore(ASTNode node, VariableResolverFactory factory) {
((WithNode) node).getNestedStatement().getValue(null, factory);
factory.createVariable("mod", "FOOBAR!");
return 0;
}
public int doAfter(Object val, ASTNode node, VariableResolverFactory factory) {
return 0;
}
});
macros.put("modify", new Macro() {
public String doMacro() {
return "@Modify with";
}
});
ExpressionCompiler compiler = new ExpressionCompiler(parseMacros("System.out.println('hello');\n" + "System.out.println('bye');\n" + "modify (foo) { aValue = 'poo', \n" + " aValue = 'poo' };\n mod", macros));
// compiler.setDebugSymbols(true);
ParserContext ctx = new ParserContext(null, interceptors, null);
ctx.setSourceFile("test.mv");
ctx.setDebugSymbols(true);
CompiledExpression compiled = compiler.compile(ctx);
MVELRuntime.setThreadDebugger(new Debugger() {
public int onBreak(Frame frame) {
System.out.println(frame.getSourceName() + ":" + frame.getLineNumber());
return Debugger.STEP;
}
});
MVELRuntime.registerBreakpoint("test.mv", 3);
System.out.println(DebugTools.decompile(compiled));
Assert.assertEquals("FOOBAR!", MVEL.executeDebugger(compiled, null, new MapVariableResolverFactory(vars)));
}
use of org.mvel2.ast.ASTNode in project mvel by mikebrock.
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));
}
Aggregations