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);
     }
 }