コード例 #1
0
        /// <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));
            }
        }
コード例 #2
0
ファイル: Decompiler.cs プロジェクト: bin-y/ecmascript-net
        /// <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());
        }