/**
* 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.mvel2.debug;
import org.mvel2.Operator;
import org.mvel2.ast.ASTNode;
import org.mvel2.ast.BinaryOperation;
import org.mvel2.ast.NestedStatement;
import org.mvel2.ast.Substatement;
import org.mvel2.compiler.CompiledExpression;
import org.mvel2.compiler.ExecutableAccessor;
import org.mvel2.compiler.ExecutableLiteral;
import org.mvel2.integration.VariableResolver;
import org.mvel2.integration.VariableResolverFactory;
import org.mvel2.util.ASTIterator;
import org.mvel2.util.ASTLinkedList;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import static org.mvel2.Operator.ADD;
import static org.mvel2.Operator.SUB;
/**
* @author Christopher Brock
*/
public class DebugTools {
public static String decompile(Serializable expr) {
if (expr instanceof CompiledExpression) return decompile((CompiledExpression) expr);
else if (expr instanceof ExecutableAccessor)
return "CANNOT DECOMPILE OPTIMIZED STATEMENT (Run with -Dmvel.optimizer=false)";
else if (expr instanceof ExecutableLiteral) {
return "LITERAL: " + ((ExecutableLiteral) expr).getValue(null, null);
}
else return "NOT A KNOWN PAYLOAD: " + expr.getClass().getName();
}
public static String decompile(CompiledExpression cExp) {
return decompile(cExp, false, new DecompileContext());
}
private static final class DecompileContext {
public int node = 0;
}
private static String decompile(CompiledExpression cExp, boolean nest, DecompileContext context) {
ASTIterator iter = new ASTLinkedList(cExp.getFirstNode());
ASTNode tk;
StringBuffer sbuf = new StringBuffer();
if (!nest) {
sbuf.append("Expression Decompile\n-------------\n");
}
while (iter.hasMoreNodes()) {
sbuf.append("(").append(context.node++).append(") ");
if ((tk = iter.nextNode()) instanceof NestedStatement
&& ((NestedStatement) tk).getNestedStatement() instanceof CompiledExpression) {
//noinspection StringConcatenationInsideStringBufferAppend
sbuf.append("NEST [" + tk.getClass().getSimpleName() + "]: { " + tk.getName() + " }\n");
sbuf.append(decompile((CompiledExpression) ((NestedStatement) tk).getNestedStatement(), true, context));
}
if (tk instanceof Substatement
&& ((Substatement) tk).getStatement() instanceof CompiledExpression) {
//noinspection StringConcatenationInsideStringBufferAppend
sbuf.append("NEST [" + tk.getClass().getSimpleName() + "]: { " + tk.getName() + " }\n");
sbuf.append(decompile((CompiledExpression) ((Substatement) tk).getStatement(), true, context));
}
// else if (tk instanceof Function) {
// sbuf.append("FUNCTION [" + tk.getName() + "]: ")
// .append(decompile((CompiledExpression) ((Function)tk).getCompiledBlock(), true, context));
// }
else if (tk.isDebuggingSymbol()) {
//noinspection StringConcatenationInsideStringBufferAppend
sbuf.append("DEBUG_SYMBOL :: " + tk.toString());
}
else if (tk.isLiteral()) {
sbuf.append("LITERAL :: ").append(tk.getLiteralValue()).append("'");
}
else if (tk.isOperator()) {
sbuf.append("OPERATOR [").append(getOperatorName(tk.getOperator())).append("]: ")
.append(tk.getName());
if (tk.isOperator(Operator.END_OF_STMT)) sbuf.append("\n");
}
else if (tk.isIdentifier()) {
sbuf.append("REFERENCE :: ").append(tk.getClass().getSimpleName()).append(":").append(tk.getName());
}
else if (tk instanceof BinaryOperation) {
BinaryOperation bo = (BinaryOperation) tk;
sbuf.append("OPERATION [" + getOperatorName(bo.getOperation()) + "] {").append(bo.getLeft().getName())
.append("} {").append(bo.getRight().getName()).append("}");
}
else {
//noinspection StringConcatenationInsideStringBufferAppend
sbuf.append("NODE [" + tk.getClass().getSimpleName() + "] :: " + tk.getName());
}
sbuf.append("\n");
}
sbuf.append("==END==");
return sbuf.toString();
}
public static String getOperatorSymbol(int operator) {
switch (operator) {
case ADD:
return "+";
case SUB:
return "-";
case Operator.ASSIGN:
return "=";
case Operator.ASSIGN_ADD:
return "=+";
case Operator.ASSIGN_STR_APPEND:
return "=+";
case Operator.ASSIGN_SUB:
return "=";
case Operator.BW_AND:
return "&";
case Operator.BW_OR:
return "|";
case Operator.BW_SHIFT_LEFT:
return "<<";
case Operator.BW_SHIFT_RIGHT:
return ">>";
case Operator.BW_USHIFT_LEFT:
return "<<<";
case Operator.BW_USHIFT_RIGHT:
return ">>>";
case Operator.BW_XOR:
return "^";
case Operator.CONTAINS:
return "contains";
case Operator.CONVERTABLE_TO:
return "convertable_to";
case Operator.DEC:
return "--";
case Operator.DEC_ASSIGN:
return "++";
case Operator.DIV:
return "/";
case Operator.DO:
return "do";
case Operator.ELSE:
return "else";
case Operator.END_OF_STMT:
return ";";
case Operator.EQUAL:
return "==";
case Operator.FOR:
return "for";
case Operator.FOREACH:
return "foreach";
case Operator.FUNCTION:
return "function";
case Operator.GETHAN:
return ">=";
case Operator.GTHAN:
return ">";
case Operator.IF:
return "if";
case Operator.INC:
return "++";
case Operator.INC_ASSIGN:
return "++";
case Operator.INSTANCEOF:
return "instanceof";
case Operator.LETHAN:
return "<=";
case Operator.LTHAN:
return "<";
case Operator.MOD:
return "%";
case Operator.MULT:
return "*";
case Operator.NEQUAL:
return "!=";
case Operator.NEW:
return "new";
case Operator.AND:
return "&&";
case Operator.OR:
return "||";
case Operator.POWER:
return "**";
case Operator.PROJECTION:
return "PROJECT";
case Operator.REGEX:
return "REGEX";
case Operator.RETURN:
return "RETURN";
case Operator.SIMILARITY:
return "SIMILARITY";
case Operator.SOUNDEX:
return "SOUNDEX";
case Operator.STR_APPEND:
return "+";
case Operator.SWITCH:
return "SWITCH";
case Operator.TERNARY:
return "TERNARY_IF";
case Operator.TERNARY_ELSE:
return "TERNARY_ELSE";
case Operator.WHILE:
return "while";
case Operator.CHOR:
return "or";
}
return "UNKNOWN_OPERATOR";
}
public static String getOperatorName(int operator) {
switch (operator) {
case ADD:
return "ADD";
case SUB:
return "SUBTRACT";
case Operator.ASSIGN:
return "ASSIGN";
case Operator.ASSIGN_ADD:
return "ASSIGN_ADD";
case Operator.ASSIGN_STR_APPEND:
return "ASSIGN_STR_APPEND";
case Operator.ASSIGN_SUB:
return "ASSIGN_SUB";
case Operator.BW_AND:
return "BIT_AND";
case Operator.BW_OR:
return "BIT_OR";
case Operator.BW_SHIFT_LEFT:
return "BIT_SHIFT_LEFT";
case Operator.BW_SHIFT_RIGHT:
return "BIT_SHIFT_RIGHT";
case Operator.BW_USHIFT_LEFT:
return "BIT_UNSIGNED_SHIFT_LEFT";
case Operator.BW_USHIFT_RIGHT:
return "BIT_UNSIGNED_SHIFT_RIGHT";
case Operator.BW_XOR:
return "BIT_XOR";
case Operator.CONTAINS:
return "CONTAINS";
case Operator.CONVERTABLE_TO:
return "CONVERTABLE_TO";
case Operator.DEC:
return "DECREMENT";
case Operator.DEC_ASSIGN:
return "DECREMENT_ASSIGN";
case Operator.DIV:
return "DIVIDE";
case Operator.DO:
return "DO";
case Operator.ELSE:
return "ELSE";
case Operator.END_OF_STMT:
return "END_OF_STATEMENT";
case Operator.EQUAL:
return "EQUAL";
case Operator.FOR:
return "FOR";
case Operator.FOREACH:
return "FOREACH";
case Operator.FUNCTION:
return "FUNCTION";
case Operator.GETHAN:
return "GREATER_THAN_OR_EQUAL";
case Operator.GTHAN:
return "GREATHER_THAN";
case Operator.IF:
return "IF";
case Operator.INC:
return "INCREMENT";
case Operator.INC_ASSIGN:
return "INCREMENT_ASSIGN";
case Operator.INSTANCEOF:
return "INSTANCEOF";
case Operator.LETHAN:
return "LESS_THAN_OR_EQUAL";
case Operator.LTHAN:
return "LESS_THAN";
case Operator.MOD:
return "MODULUS";
case Operator.MULT:
return "MULTIPLY";
case Operator.NEQUAL:
return "NOT_EQUAL";
case Operator.NEW:
return "NEW_OBJECT";
case Operator.AND:
return "AND";
case Operator.OR:
return "OR";
case Operator.POWER:
return "POWER_OF";
case Operator.PROJECTION:
return "PROJECT";
case Operator.REGEX:
return "REGEX";
case Operator.RETURN:
return "RETURN";
case Operator.SIMILARITY:
return "SIMILARITY";
case Operator.SOUNDEX:
return "SOUNDEX";
case Operator.STR_APPEND:
return "STR_APPEND";
case Operator.SWITCH:
return "SWITCH";
case Operator.TERNARY:
return "TERNARY_IF";
case Operator.TERNARY_ELSE:
return "TERNARY_ELSE";
case Operator.WHILE:
return "WHILE";
case Operator.CHOR:
return "CHAINED_OR";
}
return "UNKNOWN_OPERATOR";
}
public static Class determineType(String name, CompiledExpression compiledExpression) {
ASTIterator iter = new ASTLinkedList(compiledExpression.getFirstNode());
ASTNode node;
while (iter.hasMoreNodes()) {
if (name.equals((node = iter.nextNode()).getName()) && node.isAssignment()) {
return node.getEgressType();
}
}
return null;
}
public static Map<String, VariableResolver> getAllVariableResolvers(VariableResolverFactory rootFactory) {
Map<String, VariableResolver> allVariableResolvers = new HashMap<String, VariableResolver>();
VariableResolverFactory vrf = rootFactory;
do {
for (String var : vrf.getKnownVariables()) {
allVariableResolvers.put(var, vrf.getVariableResolver(var));
}
}
while ((vrf = vrf.getNextFactory()) != null);
return allVariableResolvers;
}
}