/** * 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"; case Operator.STACKLANG: return "stacklang"; } 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"; case Operator.STACKLANG: return "STACKLANG"; } 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; } }