001: /**
002: * MVEL (The MVFLEX Expression Language)
003: *
004: * Copyright (C) 2007 Christopher Brock, MVFLEX/Valhalla Project and the Codehaus
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: *
018: */package org.mvel.debug;
019:
020: import org.mvel.Operator;
021: import static org.mvel.Operator.ADD;
022: import static org.mvel.Operator.SUB;
023: import org.mvel.ast.ASTNode;
024: import org.mvel.ast.BinaryOperation;
025: import org.mvel.ast.NestedStatement;
026: import org.mvel.ast.Substatement;
027: import org.mvel.compiler.CompiledExpression;
028: import org.mvel.compiler.ExecutableAccessor;
029: import org.mvel.compiler.ExecutableLiteral;
030: import org.mvel.integration.VariableResolver;
031: import org.mvel.integration.VariableResolverFactory;
032: import org.mvel.util.ASTIterator;
033: import static org.mvel.util.ParseTools.getSimpleClassName;
034:
035: import java.io.Serializable;
036: import java.util.HashMap;
037: import java.util.Map;
038:
039: /**
040: * @author Christopher Brock
041: */
042: public class DebugTools {
043:
044: public static String decompile(Serializable expr) {
045: if (expr instanceof CompiledExpression)
046: return decompile((CompiledExpression) expr);
047: else if (expr instanceof ExecutableAccessor)
048: return "CANNOT DECOMPILE OPTIMIZED STATEMENT (Run with -Dmvel.optimizer=false)";
049: else if (expr instanceof ExecutableLiteral) {
050: return "LITERAL: "
051: + ((ExecutableLiteral) expr).getValue(null, null);
052: } else
053: return "NOT A KNOWN PAYLOAD: " + expr.getClass().getName();
054: }
055:
056: public static String decompile(CompiledExpression cExp) {
057: return decompile(cExp, false, new DecompileContext());
058: }
059:
060: private static final class DecompileContext {
061: public int node = 0;
062: }
063:
064: private static String decompile(CompiledExpression cExp,
065: boolean nest, DecompileContext context) {
066: ASTIterator iter = cExp.getInstructions();
067: ASTNode tk;
068:
069: // int node = 0;
070:
071: StringBuffer sbuf = new StringBuffer();
072:
073: if (!nest) {
074: sbuf.append("Expression Decompile\n-------------\n");
075: }
076:
077: while (iter.hasMoreNodes()) {
078: tk = iter.nextNode();
079:
080: sbuf.append("(").append(context.node++).append(") ");
081:
082: if (tk instanceof NestedStatement
083: && ((NestedStatement) tk).getNestedStatement() instanceof CompiledExpression) {
084: //noinspection StringConcatenationInsideStringBufferAppend
085: sbuf.append("NEST ["
086: + getSimpleClassName(tk.getClass()) + "]: { "
087: + tk.getName() + " }\n");
088: sbuf.append(decompile(
089: (CompiledExpression) ((NestedStatement) tk)
090: .getNestedStatement(), true, context));
091: }
092: if (tk instanceof Substatement
093: && ((Substatement) tk).getStatement() instanceof CompiledExpression) {
094: //noinspection StringConcatenationInsideStringBufferAppend
095: sbuf.append("NEST ["
096: + getSimpleClassName(tk.getClass()) + "]: { "
097: + tk.getName() + " }\n");
098: sbuf.append(decompile(
099: (CompiledExpression) ((Substatement) tk)
100: .getStatement(), true, context));
101: } else if (tk.isDebuggingSymbol()) {
102: //noinspection StringConcatenationInsideStringBufferAppend
103: sbuf.append("DEBUG_SYMBOL :: " + tk.toString());
104: } else if (tk.isLiteral()) {
105: sbuf.append("LITERAL :: ").append(tk.getLiteralValue())
106: .append("'");
107: } else if (tk.isOperator()) {
108: sbuf.append("OPERATOR [").append(
109: getOperatorName(tk.getOperator()))
110: .append("]: ").append(tk.getName());
111:
112: if (tk.isOperator(Operator.END_OF_STMT))
113: sbuf.append("\n");
114: } else if (tk.isIdentifier()) {
115: sbuf.append("REFERENCE :: ").append(
116: getSimpleClassName(tk.getClass())).append(":")
117: .append(tk.getName());
118: } else if (tk instanceof BinaryOperation) {
119: BinaryOperation bo = (BinaryOperation) tk;
120: sbuf.append(
121: "OPERATION ["
122: + getOperatorName(bo.getOperation())
123: + "] {").append(bo.getLeft().getName())
124: .append("} {").append(bo.getRight().getName())
125: .append("}");
126: } else {
127: //noinspection StringConcatenationInsideStringBufferAppend
128: sbuf.append("NODE ["
129: + getSimpleClassName(tk.getClass()) + "] :: "
130: + tk.getName());
131: }
132:
133: sbuf.append("\n");
134:
135: }
136:
137: sbuf.append("==END==");
138:
139: return sbuf.toString();
140: }
141:
142: public static String getOperatorName(int operator) {
143: switch (operator) {
144: case ADD:
145: return "ADD";
146: case SUB:
147: return "SUBTRACT";
148: case Operator.ASSIGN:
149: return "ASSIGN";
150: case Operator.ASSIGN_ADD:
151: return "ASSIGN_ADD";
152: case Operator.ASSIGN_STR_APPEND:
153: return "ASSIGN_STR_APPEND";
154: case Operator.ASSIGN_SUB:
155: return "ASSIGN_SUB";
156: case Operator.BW_AND:
157: return "BIT_AND";
158: case Operator.BW_OR:
159: return "BIT_OR";
160: case Operator.BW_SHIFT_LEFT:
161: return "BIT_SHIFT_LEFT";
162: case Operator.BW_SHIFT_RIGHT:
163: return "BIT_SHIFT_RIGHT";
164: case Operator.BW_USHIFT_LEFT:
165: return "BIT_UNSIGNED_SHIFT_LEFT";
166: case Operator.BW_USHIFT_RIGHT:
167: return "BIT_UNSIGNED_SHIFT_RIGHT";
168: case Operator.BW_XOR:
169: return "BIT_XOR";
170: case Operator.CONTAINS:
171: return "CONTAINS";
172: case Operator.CONVERTABLE_TO:
173: return "CONVERTABLE_TO";
174: case Operator.DEC:
175: return "DECREMENT";
176: case Operator.DEC_ASSIGN:
177: return "DECREMENT_ASSIGN";
178: case Operator.DIV:
179: return "DIVIDE";
180: case Operator.DO:
181: return "DO";
182: case Operator.ELSE:
183: return "ELSE";
184: case Operator.END_OF_STMT:
185: return "END_OF_STATEMENT";
186: case Operator.EQUAL:
187: return "EQUAL";
188: case Operator.FOR:
189: return "FOR";
190: case Operator.FOREACH:
191: return "FOREACH";
192: case Operator.FUNCTION:
193: return "FUNCTION";
194: case Operator.GETHAN:
195: return "GREATER_THAN_OR_EQUAL";
196: case Operator.GTHAN:
197: return "GREATHER_THAN";
198: case Operator.IF:
199: return "IF";
200: case Operator.INC:
201: return "INCREMENT";
202: case Operator.INC_ASSIGN:
203: return "INCREMENT_ASSIGN";
204: case Operator.INSTANCEOF:
205: return "INSTANCEOF";
206: case Operator.LETHAN:
207: return "LESS_THAN_OR_EQUAL";
208: case Operator.LTHAN:
209: return "LESS_THAN";
210: case Operator.MOD:
211: return "MODULUS";
212: case Operator.MULT:
213: return "MULTIPLY";
214: case Operator.NEQUAL:
215: return "NOT_EQUAL";
216: case Operator.NEW:
217: return "NEW_OBJECT";
218: case Operator.OR:
219: return "OR";
220: case Operator.POWER:
221: return "POWER_OF";
222: case Operator.PROJECTION:
223: return "PROJECT";
224: case Operator.REGEX:
225: return "REGEX";
226: case Operator.RETURN:
227: return "RETURN";
228: case Operator.SIMILARITY:
229: return "SIMILARITY";
230: case Operator.SOUNDEX:
231: return "SOUNDEX";
232: case Operator.STR_APPEND:
233: return "STR_APPEND";
234: case Operator.SWITCH:
235: return "SWITCH";
236: case Operator.TERNARY:
237: return "TERNARY_IF";
238: case Operator.TERNARY_ELSE:
239: return "TERNARY_ELSE";
240: case Operator.WHILE:
241: return "WHILE";
242: case Operator.CHOR:
243: return "CHAINED_OR";
244: }
245:
246: return "UNKNOWN_OPERATOR";
247: }
248:
249: public static Class determineType(String name,
250: CompiledExpression compiledExpression) {
251: ASTIterator iter = compiledExpression.getTokenIterator();
252: ASTNode node;
253: while (iter.hasMoreNodes()) {
254: if (name.equals((node = iter.nextNode()).getName())
255: && node.isAssignment()) {
256: return node.getEgressType();
257: }
258: }
259:
260: return null;
261: }
262:
263: public static Map<String, VariableResolver> getAllVariableResolvers(
264: VariableResolverFactory rootFactory) {
265:
266: Map<String, VariableResolver> allVariableResolvers = new HashMap<String, VariableResolver>();
267:
268: VariableResolverFactory vrf = rootFactory;
269: do {
270: for (String var : vrf.getKnownVariables()) {
271: allVariableResolvers.put(var, vrf
272: .getVariableResolver(var));
273:
274: }
275: } while ((vrf = vrf.getNextFactory()) != null);
276:
277: return allVariableResolvers;
278: }
279:
280: }
|