internal static int [] getLineNumbers (InterpreterData data) { UintMap presentLines = new UintMap (); sbyte [] iCode = data.itsICode; int iCodeLength = iCode.Length; for (int pc = 0; pc != iCodeLength; ) { int bytecode = iCode [pc]; int span = bytecodeSpan (bytecode); if (bytecode == Icode_LINE) { if (span != 3) Context.CodeBug (); int line = GetIndex (iCode, pc + 1); presentLines.put (line, 0); } pc += span; } return presentLines.Keys; }
/// <summary> Decompile the source information associated with this js /// function/script back into a string. For the most part, this /// just means translating tokens back to their string /// representations; there's a little bit of lookahead logic to /// decide the proper spacing/indentation. Most of the work in /// mapping the original source to the prettyprinted decompiled /// version is done by the parser. /// /// </summary> /// <param name="source">encoded source tree presentation /// /// </param> /// <param name="flags">flags to select output format /// /// </param> /// <param name="properties">indentation properties /// /// </param> public static string Decompile(string source, int flags, UintMap properties) { int length = source.Length; if (length == 0) { return ""; } int indent = properties.getInt(INITIAL_INDENT_PROP, 0); if (indent < 0) throw new ArgumentException(); int indentGap = properties.getInt(INDENT_GAP_PROP, 4); if (indentGap < 0) throw new ArgumentException(); int caseGap = properties.getInt(CASE_GAP_PROP, 2); if (caseGap < 0) throw new ArgumentException(); System.Text.StringBuilder result = new System.Text.StringBuilder(); bool justFunctionBody = (0 != (flags & Decompiler.ONLY_BODY_FLAG)); bool toSource = (0 != (flags & Decompiler.TO_SOURCE_FLAG)); bool toString = (0 != (flags & Decompiler.TO_STRING_FLAG)); // Spew tokens in source, for debugging. // as TYPE number char if (printSource) { System.Console.Error.WriteLine("length:" + length); for (int i = 0; i < length; ++i) { // Note that tokenToName will fail unless Context.printTrees // is true. string tokenname = null; if (Token.printNames) { tokenname = Token.name(source[i]); } if (tokenname == null) { tokenname = "---"; } string pad = tokenname.Length > 7 ? "\t" : "\t\t"; System.Console.Error.WriteLine(tokenname + pad + (int)source[i] + "\t'" + ScriptRuntime.escapeString(source.Substring(i, (i + 1) - (i))) + "'"); } System.Console.Error.WriteLine(); } int braceNesting = 0; bool afterFirstEOL = false; int i2 = 0; int topFunctionType; if (source[i2] == Token.SCRIPT) { ++i2; topFunctionType = -1; } else { topFunctionType = source[i2 + 1]; } if (!toSource) { if (!toString) { // add an initial newline to exactly match js. result.Append('\n'); } for (int j = 0; j < indent; j++) result.Append(' '); } else { if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION) { result.Append('('); } } while (i2 < length) { switch (source[i2]) { case (char)(Token.NAME): case (char)(Token.REGEXP): // re-wrapped in '/'s in parser... i2 = PrintSourceString(source, i2 + 1, false, result); continue; case (char)(Token.STRING): i2 = PrintSourceString(source, i2 + 1, true, result); continue; case (char)(Token.NUMBER): i2 = PrintSourceNumber(source, i2 + 1, result); continue; case (char)(Token.TRUE): result.Append("true"); break; case (char)(Token.FALSE): result.Append("false"); break; case (char)(Token.NULL): result.Append("null"); break; case (char)(Token.THIS): result.Append("this"); break; case (char)(Token.FUNCTION): ++i2; // skip function type result.Append("function "); break; case (char)(FUNCTION_END): // Do nothing break; case (char)(Token.COMMA): result.Append(", "); break; case (char)(Token.LC): ++braceNesting; if (Token.EOL == GetNext(source, length, i2)) indent += indentGap; result.Append('{'); break; case (char)(Token.RC): { --braceNesting; /* don't print the closing RC if it closes the * toplevel function and we're called from * decompileFunctionBody. */ if (justFunctionBody && braceNesting == 0) break; result.Append('}'); switch (GetNext(source, length, i2)) { case Token.EOL: case FUNCTION_END: indent -= indentGap; break; case Token.WHILE: case Token.ELSE: indent -= indentGap; result.Append(' '); break; } break; } case (char)(Token.LP): result.Append('('); break; case (char)(Token.RP): result.Append(')'); if (Token.LC == GetNext(source, length, i2)) result.Append(' '); break; case (char)(Token.LB): result.Append('['); break; case (char)(Token.RB): result.Append(']'); break; case (char)(Token.EOL): { if (toSource) break; bool newLine = true; if (!afterFirstEOL) { afterFirstEOL = true; if (justFunctionBody) { /* throw away just added 'function name(...) {' * and restore the original indent */ result.Length = 0; indent -= indentGap; newLine = false; } } if (newLine) { result.Append('\n'); } /* add indent if any tokens remain, * less setback if next token is * a label, case or default. */ if (i2 + 1 < length) { int less = 0; int nextToken = source[i2 + 1]; if (nextToken == Token.CASE || nextToken == Token.DEFAULT) { less = indentGap - caseGap; } else if (nextToken == Token.RC) { less = indentGap; } /* elaborate check against label... skip past a * following inlined NAME and look for a COLON. */ else if (nextToken == Token.NAME) { int afterName = GetSourceStringEnd(source, i2 + 2); if (source[afterName] == Token.COLON) less = indentGap; } for (; less < indent; less++) result.Append(' '); } break; } case (char)(Token.DOT): result.Append('.'); break; case (char)(Token.NEW): result.Append("new "); break; case (char)(Token.DELPROP): result.Append("delete "); break; case (char)(Token.IF): result.Append("if "); break; case (char)(Token.ELSE): result.Append("else "); break; case (char)(Token.FOR): result.Append("for "); break; case (char)(Token.IN): result.Append(" in "); break; case (char)(Token.WITH): result.Append("with "); break; case (char)(Token.WHILE): result.Append("while "); break; case (char)(Token.DO): result.Append("do "); break; case (char)(Token.TRY): result.Append("try "); break; case (char)(Token.CATCH): result.Append("catch "); break; case (char)(Token.FINALLY): result.Append("finally "); break; case (char)(Token.THROW): result.Append("throw "); break; case (char)(Token.SWITCH): result.Append("switch "); break; case (char)(Token.BREAK): result.Append("break"); if (Token.NAME == GetNext(source, length, i2)) result.Append(' '); break; case (char)(Token.CONTINUE): result.Append("continue"); if (Token.NAME == GetNext(source, length, i2)) result.Append(' '); break; case (char)(Token.CASE): result.Append("case "); break; case (char)(Token.DEFAULT): result.Append("default"); break; case (char)(Token.RETURN): result.Append("return"); if (Token.SEMI != GetNext(source, length, i2)) result.Append(' '); break; case (char)(Token.VAR): result.Append("var "); break; case (char)(Token.SEMI): result.Append(';'); if (Token.EOL != GetNext(source, length, i2)) { // separators in FOR result.Append(' '); } break; case (char)(Token.ASSIGN): result.Append(" = "); break; case (char)(Token.ASSIGN_ADD): result.Append(" += "); break; case (char)(Token.ASSIGN_SUB): result.Append(" -= "); break; case (char)(Token.ASSIGN_MUL): result.Append(" *= "); break; case (char)(Token.ASSIGN_DIV): result.Append(" /= "); break; case (char)(Token.ASSIGN_MOD): result.Append(" %= "); break; case (char)(Token.ASSIGN_BITOR): result.Append(" |= "); break; case (char)(Token.ASSIGN_BITXOR): result.Append(" ^= "); break; case (char)(Token.ASSIGN_BITAND): result.Append(" &= "); break; case (char)(Token.ASSIGN_LSH): result.Append(" <<= "); break; case (char)(Token.ASSIGN_RSH): result.Append(" >>= "); break; case (char)(Token.ASSIGN_URSH): result.Append(" >>>= "); break; case (char)(Token.HOOK): result.Append(" ? "); break; case (char)(Token.OBJECTLIT): // pun OBJECTLIT to mean colon in objlit property // initialization. // This needs to be distinct from COLON in the general case // to distinguish from the colon in a ternary... which needs // different spacing. result.Append(':'); break; case (char)(Token.COLON): if (Token.EOL == GetNext(source, length, i2)) // it's the end of a label result.Append(':'); // it's the middle part of a ternary else result.Append(" : "); break; case (char)(Token.OR): result.Append(" || "); break; case (char)(Token.AND): result.Append(" && "); break; case (char)(Token.BITOR): result.Append(" | "); break; case (char)(Token.BITXOR): result.Append(" ^ "); break; case (char)(Token.BITAND): result.Append(" & "); break; case (char)(Token.SHEQ): result.Append(" === "); break; case (char)(Token.SHNE): result.Append(" !== "); break; case (char)(Token.EQ): result.Append(" == "); break; case (char)(Token.NE): result.Append(" != "); break; case (char)(Token.LE): result.Append(" <= "); break; case (char)(Token.LT): result.Append(" < "); break; case (char)(Token.GE): result.Append(" >= "); break; case (char)(Token.GT): result.Append(" > "); break; case (char)(Token.INSTANCEOF): result.Append(" instanceof "); break; case (char)(Token.LSH): result.Append(" << "); break; case (char)(Token.RSH): result.Append(" >> "); break; case (char)(Token.URSH): result.Append(" >>> "); break; case (char)(Token.TYPEOF): result.Append("typeof "); break; case (char)(Token.VOID): result.Append("void "); break; case (char)(Token.NOT): result.Append('!'); break; case (char)(Token.BITNOT): result.Append('~'); break; case (char)(Token.POS): result.Append('+'); break; case (char)(Token.NEG): result.Append('-'); break; case (char)(Token.INC): result.Append("++"); break; case (char)(Token.DEC): result.Append("--"); break; case (char)(Token.ADD): result.Append(" + "); break; case (char)(Token.SUB): result.Append(" - "); break; case (char)(Token.MUL): result.Append(" * "); break; case (char)(Token.DIV): result.Append(" / "); break; case (char)(Token.MOD): result.Append(" % "); break; case (char)(Token.COLONCOLON): result.Append("::"); break; case (char)(Token.DOTDOT): result.Append(".."); break; case (char)(Token.DOTQUERY): result.Append(".("); break; case (char)(Token.XMLATTR): result.Append('@'); break; default: // If we don't know how to decompile it, raise an exception. throw new ApplicationException(); } ++i2; } if (!toSource) { // add that trailing newline if it's an outermost function. if (!justFunctionBody && !toString) result.Append('\n'); } else { if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION) { result.Append(')'); } } return result.ToString(); }
/// <param name="indent">How much to indent the decompiled result /// /// </param> /// <param name="flags">Flags specifying format of decompilation output /// </param> internal override string Decompile(int indent, int flags) { string encodedSource = EncodedSource; if (encodedSource == null) { return base.Decompile (indent, flags); } else { UintMap properties = new UintMap (1); properties.put (Decompiler.INITIAL_INDENT_PROP, indent); return Decompiler.Decompile (encodedSource, flags, properties); } }