org.mule.mvel2.ast.WithNode Maven / Gradle / Ivy
Go to download
MVEL is a powerful expression language for Java-based applications.
It provides a plethora of features and is suited for everything
from the smallest property binding and extraction, to full blown scripts.
This is a fork of MVEL customized for use in Mule.
/**
* MVEL 2.0
* Copyright (C) 2007 The Codehaus
* Mike Brock, Dhanji Prasanna, John Graham, Mark Proctor
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mule.mvel2.ast;
import org.mule.mvel2.CompileException;
import org.mule.mvel2.MVEL;
import org.mule.mvel2.Operator;
import org.mule.mvel2.ParserContext;
import org.mule.mvel2.compiler.ExecutableStatement;
import org.mule.mvel2.integration.VariableResolverFactory;
import org.mule.mvel2.util.ErrorUtil;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import static org.mule.mvel2.util.ParseTools.*;
import static org.mule.mvel2.util.PropertyTools.getReturnType;
/**
* @author Christopher Brock
*/
public class WithNode extends BlockNode implements NestedStatement {
protected String nestParm;
// protected ExecutableStatement nestedStatement;
protected ParmValuePair[] withExpressions;
public WithNode(char[] expr, int start, int offset, int blockStart, int blockOffset, int fields, ParserContext pCtx) {
super(pCtx);
nestParm = createStringTrimmed(this.expr = expr, this.start = start, this.offset = offset);
this.blockStart = blockStart;
this.blockOffset = blockOffset;
if ((fields & COMPILE_IMMEDIATE) != 0) {
pCtx.setBlockSymbols(true);
egressType = (compiledBlock = (ExecutableStatement)
subCompileExpression(expr, start, offset, pCtx)).getKnownEgressType();
withExpressions = compileWithExpressions(expr, blockStart, blockOffset, nestParm, egressType, pCtx);
pCtx.setBlockSymbols(false);
}
}
public Object getReducedValueAccelerated(Object ctx, Object thisValue, VariableResolverFactory factory) {
Object ctxObject = compiledBlock.getValue(ctx, thisValue, factory);
if (ctxObject == null) throw new CompileException("with-block against null pointer", expr, start);
for (ParmValuePair pvp : withExpressions) {
pvp.eval(ctxObject, factory);
}
return ctxObject;
}
public Object getReducedValue(Object ctx, Object thisValue, VariableResolverFactory factory) {
parseWithExpressions(nestParm, expr, blockStart, blockOffset, ctx = MVEL.eval(expr, start, offset, ctx, factory), factory);
return ctx;
}
public static ParmValuePair[] compileWithExpressions(char[] block, int start, int offset, String nestParm, Class egressType, ParserContext pCtx) {
/**
*
* MAINTENANCE NOTE: AN INTERPRETED MODE VERSION OF THIS CODE IS DUPLICATED IN: ParseTools
*
*/
List parms = new ArrayList();
String parm = "";
int end = start + offset;
int _st = start;
int _end = -1;
int oper = -1;
for (int i = start; i < end; i++) {
switch (block[i]) {
case '{':
case '[':
case '(':
case '\'':
case '"':
i = balancedCapture(block, i, end, block[i]);
continue;
case '/':
if (i < end && block[i + 1] == '/') {
while (i < end && block[i] != '\n') block[i++] = ' ';
if (parm == null) _st = i;
}
else if (i < end && block[i + 1] == '*') {
int len = end - 1;
while (i < len && !(block[i] == '*' && block[i + 1] == '/')) {
block[i++] = ' ';
}
block[i++] = ' ';
block[i++] = ' ';
if (parm == null) _st = i;
}
else if (i < end && block[i + 1] == '=') {
oper = Operator.DIV;
}
continue;
case '%':
case '*':
case '-':
case '+':
if (i + 1 < end && block[i + 1] == '=') {
oper = opLookup(block[i]);
}
continue;
case '=':
parm = createStringTrimmed(block, _st, i - _st - (oper != -1 ? 1 : 0));
_st = i + 1;
continue;
case ',':
if (_end == -1) _end = i;
if (parm == null || parm.length() == 0) {
try {
String expr;
if (nestParm == null) {
expr = new String(block, _st, _end - _st);
}
else {
expr = new StringBuilder(nestParm).append('.')
.append(new String(block, _st, _end - _st)).toString();
}
parms.add(
new ParmValuePair(null, (ExecutableStatement)
subCompileExpression(expr, pCtx),
egressType, pCtx)
);
}
catch (CompileException e) {
e.setCursor(_st + (e.getCursor() - (e.getExpr().length - offset)));
e.setExpr(block);
throw e;
}
oper = -1;
_st = ++i;
}
else {
if (nestParm == null) {
throw new CompileException("operative assignment not possible here", block, start);
}
try {
parms.add(new ParmValuePair(
parm,
oper != -1 ?
(ExecutableStatement) subCompileExpression(
createShortFormOperativeAssignment(nestParm + "." + parm,
block, _st, _end - _st, oper), pCtx)
//or
: (ExecutableStatement) subCompileExpression(block, _st, _end - _st, pCtx)
, egressType, pCtx));
}
catch (CompileException e) {
e.setCursor(_st + (e.getCursor() - (e.getExpr().length - offset)));
e.setExpr(block);
throw e;
}
parm = null;
oper = -1;
_st = ++i;
}
_end = -1;
break;
}
}
if (_st != (_end = end)) {
try {
if (parm == null || "".equals(parm)) {
String expr;
if (nestParm == null) {
expr = new String(block, _st, _end - _st);
}
else {
expr = new StringBuilder(nestParm).append('.')
.append(new String(block, _st, _end - _st)).toString();
}
parms.add(
new ParmValuePair(null, (ExecutableStatement)
subCompileExpression(expr, pCtx),
egressType, pCtx)
);
}
else {
if (nestParm == null) {
throw new CompileException("operative assignment not possible here", block, start);
}
parms.add(new ParmValuePair(
parm,
oper != -1 ?
(ExecutableStatement) subCompileExpression(
createShortFormOperativeAssignment(nestParm + "." + parm, block, _st, _end - _st, oper),
pCtx)
//or
: (ExecutableStatement) subCompileExpression(block, _st, _end - _st, pCtx)
, egressType, pCtx));
}
}
catch (CompileException e) {
throw ErrorUtil.rewriteIfNeeded(e, block, _st);
}
}
ParmValuePair[] withExpressions;
parms.toArray(withExpressions = new ParmValuePair[parms.size()]);
return withExpressions;
}
public ExecutableStatement getNestedStatement() {
return compiledBlock;
}
public ParmValuePair[] getWithExpressions() {
return withExpressions;
}
public static final class ParmValuePair implements Serializable {
private Serializable setExpression;
private ExecutableStatement statement;
public ParmValuePair(String parameter, ExecutableStatement statement, Class ingressType, ParserContext pCtx) {
if (parameter != null && parameter.length() != 0) {
this.setExpression = MVEL.compileSetExpression(parameter,
ingressType != null ? getReturnType(ingressType, parameter, pCtx) : Object.class
, pCtx);
}
this.statement = statement;
}
public Serializable getSetExpression() {
return setExpression;
}
public ExecutableStatement getStatement() {
return statement;
}
public void eval(Object ctx, VariableResolverFactory factory) {
if (setExpression == null) {
this.statement.getValue(ctx, factory);
}
else {
MVEL.executeSetExpression(setExpression, ctx, factory, this.statement.getValue(ctx, factory));
}
}
}
}