public void emit(IToken tok)
        {
            //This (the token having no text) might occur with an empty semicolon token (semic).  I think nothing needs to be done here and
            //no state needs to be saved.
            if (tok.Text==null)
                return;
        
            //look at hidden tokens to see if the tag to turn off formatting is seen.  If so, then just emit all the hidden tokens and
            //the main token.  Want to let operations happen that don't insert text and maintain state that we need to keep.  
        
            int currentBufferOffset=mOutputBuffer.Length;
            mLastToken=tok;
            //handle whitespace
            CommonTokenStream tokens=mRawTokens;//(CommonTokenStream)getTokenStream();
            int currentTokenIndex=((CommonToken)tok).TokenIndex-1;
            List<IToken> hiddenTokens = new List<IToken>();
        
            //collect all of the hidden tokens since the last non-whitespace token
            while (currentTokenIndex>=0)
            {
                IToken t = tokens.Get(currentTokenIndex);
                if (t.Channel==Token.DEFAULT_CHANNEL)
                    break;
                hiddenTokens.Add(t);
                currentTokenIndex--;
            }

            IToken[] rev = hiddenTokens.ToArray();
            Array.Reverse(rev);
            hiddenTokens.Clear();
            hiddenTokens.AddRange(rev);
        
            if (!mProcessingBindableTag && mBindableMode && mBindablePos>=0 && getFormatMode()==FORMAT_ALL)
            {
                //TODO: figure out how a partial range will figure into this.  I may have to shift the position if it's already
                //been set
                while (mBindablePos<mOutputBuffer.Length)
                {
                    char c=mOutputBuffer[mBindablePos];
                    if (!AntlrUtilities.isASWhitespace(c))
                        break;
                    mBindablePos++;
                }
                while (mBindablePos>0)
                {
                    char c=mOutputBuffer[mBindablePos-1];
                    if (c=='\n')
                        break;
                    mBindablePos--;
                }
                String bindableText = mOutputBuffer.ToString().Substring(mBindablePos);
                mOutputBuffer.Remove(mBindablePos, mOutputBuffer.Length - mBindablePos);
            
                //this should spit out the blank lines before function and similar whitespace
                printNecessaryWS(mOutputBuffer);
            
                mOutputBuffer.Append(bindableText);
                mBindableMode=false;
                mBindablePos=(-1);
            
                //check for one of the next hidden tokens being a comment.  If so, we
                //have to add a newline.
                bool commentFollows=false;
                foreach (IToken token in hiddenTokens) 
                {
                    if (AntlrUtilities.asTrim(token.Text).Length>0)
                    {
                        commentFollows=true;
                        break;
                    }
                }

                //now, spit out either newline or space to separate bindable tag from bound item
                if (!commentFollows && ((!isNewlineBeforeBindableFunction() && mBindingContext==BindingContext_Function && getMetaTagsToKeepOnSameLineAsFunction().Contains(mLastBindableTagName)) || (!isNewlineBeforeBindableProperty() && mBindingContext==BindingContext_Property && getMetaTagsToKeepOnSameLineAsProperty().Contains(mLastBindableTagName))))
                {
                    insertWS(1);
                }
                else
                {
                    insertCR(false);
                }
                //if (/*isNewlineAfterBindable() || /*mMultipleBindableItems ||*/ commentFollows /*|| mLastBindableWasConditionalTag */ || (mBindingContext==BindingContext_Function && !getMetaTagsToKeepOnSameLineAsFunction().contains(mLastBindableTagName)) || (mBindingContext==BindingContext_Property && !getMetaTagsToKeepOnSameLineAsProperty().contains(mLastBindableTagName)) || mBindingContext==BindingContext_Class)
                //{
                    //insertCR(false);
                //}
                //else
                //{
                    //insertWS(1);
                //}
            }
        
            //handle user selection range
            if (mSelectedRange!=null && !mBindableMode)
            {
                if (mOutputRange==null)
                {
                    if (tok.Line>=mSelectedRange.X)
                    {
                        mOutputRange=new Point(mOutputBuffer.Length, -1);
                        mReplaceRange=new Point(0, -1);
                        IToken firstToken=tok;
                        if (hiddenTokens.Count>0)
                        {
                            firstToken=hiddenTokens[0];
                        }
                    
                        mReplaceRange.X=((CommonToken)firstToken).StartIndex;
                    }
                }
                else
                {
                    if (mOutputRange.Y<0 && tok.Line>mSelectedRange.Y)
                    {
                        mOutputRange.Y = mOutputBuffer.Length;
                    
                        IToken firstToken=tok;
                        if (hiddenTokens.Count>0)
                        {
                            firstToken=hiddenTokens[0];
                        }
                        mReplaceRange.Y=((CommonToken)firstToken).StartIndex;
                    }
                }
            }
        
            bool onBlankLine=ASFormatter.isOnlyWhitespaceOnLastLine(mOutputBuffer); //I think I can only be on a blank line at the start of the document
            int blankLines=0;
            bool needToEnsureNewLine=false;
            foreach (Int32 ws in mAddedCRs) 
            {
                if (ws==AddCR || ws==AddCR_BlankLine)
                {
                    needToEnsureNewLine=true;
                    break;
                }
            }
        
            //process hidden tokens (whitespace and comments) before this token
            bool seenCR=(mOutputBuffer.Length==0); //if 0, then we're on a new line.  Otherwise, we're at the end of the previous code token. 
            bool seenCommentText=false;
            for (int ti=0;ti<hiddenTokens.Count;ti++)
            {
                if (seenCR)
                    captureBraceStartPos();
            
                IToken t=hiddenTokens[ti];
                switch (t.Channel)
                {
                case AS3_exParser.CHANNEL_EOL:
                
                    //if we're not formatting at all, then just add the cr.
                    if (isFormatterOff())
                    {
                        insertCRIntoBuffer(mOutputBuffer);
                        break;
                    }
                
                    seenCR=true;
                    //we only want to preserve blank lines (or possibly not preserve blank lines) if we're in format mode where
                    //we're taking control of the whitespace.   
                    if (getFormatMode()==FORMAT_ALL)
                    {
                        if (isKeepBlankLines() || getBlankLinesToKeep()>blankLines)
                        {
                            if (onBlankLine)
                            {
                                //we got a carriage return but we were already on a new line.  Don't add the initial carriage
                                //return.  This happens at the start of the file or after a line comment
                                if (blankLines==0 && !ASFormatter.isOnlyWhitespaceOnLastLine(mOutputBuffer))
                                {
                                    insertCRIntoBuffer(mOutputBuffer);
                                }
                                blankLines++;
                                insertCRIntoBuffer(mOutputBuffer);
                            }
                            onBlankLine=true;
                        }
                        //if seen comment and !current line empty?
                        else if (seenCommentText && !ASFormatter.isOnlyWhitespaceOnLastLine(getOutputBuffer()))
                        {
                            insertCRIntoBuffer(mOutputBuffer);
                            onBlankLine=true;
                            blankLines=0;
                        }
                    }
                    else
                    {
                        //we're indenting (or formatting but without removing newlines), so just don't lose the CR
                        insertCRIntoBuffer(mOutputBuffer);
                        onBlankLine=true;
                    }
                    break;
                case AS3_exParser.CHANNEL_SLCOMMENT:
                    //NOTE: the single line comment contains a carriage return, so we are guaranteed to
                    //be on a new line afterward
                
                    /////////////////////// Handling of "exclude from formatting" tags //////////////////////
                    if (t.Text.IndexOfOrdinal(mStartExcludeProcessing)>=0)
                    {
                        pushFormatterOff();
                    }
                    else if (t.Text.IndexOfOrdinal(mStopExcludeProcessing)>=0)
                    {
                        popFormatterOff();
                    }
                
                    //if not in format mode at all, then just append the comment text, clear any accumulated whitespace and exit case
                    if (isFormatterOff())
                    {
                        if (isDoFormat() && !ASFormatter.isLineEmpty(mOutputBuffer))
                            insertCRIntoBuffer(mOutputBuffer);
                        mOutputBuffer.Append(t.Text.Replace("\r\n", "\n"));
                        mAddedCRs.Clear();
                        break;
                    }
                    ///////////////////////////////////////////////////////////////////////////////////////
                
                    //if we've seen a carriage return in the whitespace, but we haven't added one yet (because the SLComment was the next line),
                    //then we need to add a CR.
                    if (onBlankLine)
                        insertCR(false);

                    //here, we check the mDoFormat flag, NOT the format stack, because we want to know if it's legal to add spaces, not
                    //whether we are currently in a "don't format" block.  We might care if we were in code, but since this
                    //is for comments I think it makes sense.
                    if (isDoFormat() && !seenCR) //if no carriage return before this comment, then it's on the same line with other text
                    {
                        addLineCommentPreSpacing(hiddenTokens, ti);
                        mOutputBuffer.Append(t.Text.Replace("\r\n", "\n"));
                    }
                    else
                    {
                        //add a lazy space so that there will be one space before the '//' if there are preceding
                        //chars on the line.  I don't know if this can ever have an effect, but it seems safest to leave it.
                        insertWS(1);
                    
                    
                        //otherwise, we add the accumulated whitespace, which may include multiple blank lines, as we push
                        //the comment down to be with the following statement
                        printNecessaryWS(mOutputBuffer);
                        int commentIndent=0;
                        if (isKeepSingleLineCommentsAtColumn1() && t.CharPositionInLine==0)
                        {
                            //do nothing; hopefully we've not added any whitespace to a blank line
                        }
                        else
                        {
                            bool addSpecialIndent=false;
                            if (tok.Type==AS3_exParser.RCURLY)
                                addSpecialIndent=true;
                            if (addSpecialIndent)
                                pushIndent(STATEMENT_INDENT);
                            commentIndent=addIndentIfAtStartOfLine(mOutputBuffer);
                            if (addSpecialIndent)
                                popIndent();
                        }
                    
                        if (isDoFormat() && isUseLineCommentWrapping())
                        {
                            //wrap comment based on max line length and current indent spaces
                            List<CommentLineWrapData> commentLines=wrapLineComment(t.Text, commentIndent, mMaxLineLength);
                            bool firstLine=true;
                            foreach (CommentLineWrapData line in commentLines) 
                            {
                                if (!firstLine)
                                {
                                    mOutputBuffer.Append(generateIndent(commentIndent));
                                    int replaceOffset=((CommonToken)t).StartIndex+line.mOriginalStartOffset;
                                    ReplacementRange range=new ReplacementRange(new Point(mOutputBuffer.Length, mOutputBuffer.Length+2), new Point(replaceOffset, replaceOffset));
                                    if (mReplaceMap==null)
                                        mReplaceMap=new Dictionary<Int32, ReplacementRange>();
                                    range.setChangedText("//", "");
                                    mReplaceMap[mOutputBuffer.Length] = range;
                                    mAdditionalTextAdded+="//";
                                    mAdditionalTextAddedAllPasses+="//";
                                }
                            
                                mOutputBuffer.Append(line.mText);
                                firstLine=false;
                            }
                        }
                        else
                        {
                            //add the actual text
                            mOutputBuffer.Append(t.Text.Replace("\r\n", "\n"));
                        }
                    }

                    onBlankLine=true;
                    blankLines=0; //make sure we note that we have just seen a carriage return
                    seenCR=true;
                    break;
                case AS3_exParser.CHANNEL_MLCOMMENT:
                
                    //if not in format mode at all, then just append the comment text, clear any accumulated whitespace and exit switch
                    if (isFormatterOff())
                    {
                        mOutputBuffer.Append(t.Text.Replace("\r\n", "\n"));
                        mAddedCRs.Clear();
                        break;
                    }
                
                    //if we've seen a carriage return in the whitespace, but we haven't added one yet (because the MLComment was the next line),
                    //then we need to add a CR.
                    if (onBlankLine)
                        insertCR(false);

                    //here, we check the mDoFormat flag, NOT the format stack, because we want to know if it's legal to add spaces, not
                    //whether we are currently in a "don't format" block.  We might care if we were in code, but since this
                    //is for comments I think it makes sense.
                    //if the comment is at the end of a line of text, and the comment doesn't span multiple lines (and we're in a mode that allows space insertion)
                    if (isDoFormat() && !seenCR && t.Text.IndexOf('\n')<0)
                    {
                        addLineCommentPreSpacing(hiddenTokens, ti);
                        mOutputBuffer.Append(t.Text);
                    }
                    else
                    {
                        seenCR=true;
                    
                        //add a lazy space so that there will be one space before the '/*' if there are preceding
                        //chars on the line.  I don't even know if this can ever have an effect, but it seems safest to leave it. 
                        insertWS(1);
                    
                        printNecessaryWS(mOutputBuffer);
                        //TODO: something else completely, which might involve adding newlines, wrapping lines, etc.
                        //    -when I wrote this for Java, I did some fancy code to determine the relative offset of
                        //    the original lines to maintain the indenting within the comment. 
                        String[] commentLines=t.Text.Split('\n');
                        int indentAmount=getIndentForNextLine(mOutputBuffer);
                        int originalIndent=0;
                        bool useReplaceRange=false;
                        if (t.Text.StartsWithOrdinal("/**"))
                        {
                            if (isUseDocCommentWrapping() && !isKeepRelativeCommentIndent())
                            {
                                commentLines=wrapMultilineComment(indentAmount, commentLines, mDocCommentCollapseLines, isDocCommentKeepBlankLines(), true, MLAsteriskStyle_All, "/**", getDocCommentHangingIndentTabs());
                                useReplaceRange=true;
                            }
                        }
                        else if (t.Text.StartsWithOrdinal("/*"))
                        {
                            if (isUseMLCommentWrapping() && !isKeepRelativeCommentIndent())
                            {
                                commentLines=wrapMultilineComment(indentAmount, commentLines, mMLCommentCollapseLines, isMLCommentKeepBlankLines(), mMLTextOnNewLines, mMLAsteriskMode, "/*", 0);
                                useReplaceRange=true;
                            }
                        }
    
                        if (isKeepRelativeCommentIndent())
                        {
                            //find original indent
                            String lineData=t.Text;
                            int prevLineEnd=mSourceData.LastIndexOf('\n', ((CommonToken)t).StartIndex);
                            if (prevLineEnd<0)
                                prevLineEnd=0;
                            else
                                prevLineEnd++; //move to start of next line
                            lineData.Insert(0, mSourceData.Substring(prevLineEnd, ((CommonToken)t).StartIndex - prevLineEnd));
                            originalIndent=findIndent(lineData, getTabSize());
                        }
                    
                        Point replaceArea=new Point(mOutputBuffer.Length, -1);
                        for (int j=0;j<commentLines.Length;j++)
                        {
                            bool onLastLine=(j==commentLines.Length-1);
                            indentAmount=getIndentForNextLine(mOutputBuffer);
                            String data=AntlrUtilities.asTrim(commentLines[j]); //this removes the \r, if it exists
                        
                            if (j>0)
                            {
                                if (isKeepRelativeCommentIndent() && originalIndent>=0)
                                {
                                    int existingIndent=findIndent(commentLines[j], getTabSize());
                                    indentAmount=Math.Max(0, indentAmount+(existingIndent-originalIndent));
                                }
                                else //using rules assuming '*' lines
                                {
                                    if (onLastLine && data.StartsWithOrdinal("*/")) //if we're on the last line and there's more than one line
                                    {
                                        if (mIndentMultilineComments) indentAmount += 1;
                                        else indentAmount += 0;
                                    }
                                    else
                                    {
                                        //on a middle line, we have 2 cases.  If the line starts with an asterisk, then attempt to line the
                                        //asterisk up with the asterisk on the first line.  Otherwise, indent the text to the right of the open asterisk.
                                        //String nextLine=data;
                                        //if (nextLine.Length>0 && nextLine[0]=='*')
                                        //indentAmount+=1;
                                        //else
                                        //indentAmount+=3;
                                        // FIXED: Multiline comment indent support added
                                        String nextLine = data;
                                        if (nextLine.Length > 0 && nextLine[0] == '*')
                                        {
                                            if (mIndentMultilineComments) indentAmount += 1;
                                            else indentAmount += 0;
                                        }
                                        else indentAmount += 3;
                                    }
                                }
                            }
                        
                            //only add indent if not on an empty line
                            if (data.Length>0)
                            {
                                if (ASFormatter.isLineEmpty(mOutputBuffer))
                                {
                                    mOutputBuffer.Append(generateIndent(indentAmount));
                                }
                                mOutputBuffer.Append(data);
                            }
                        
                            if (!onLastLine)
                            {
                                insertCRIntoBuffer(mOutputBuffer);
                            }
                        }
                    
                        if (useReplaceRange)
                        {
                            replaceArea.Y=mOutputBuffer.Length;
                            CommonToken commonTok=(CommonToken)t;
                            for (;replaceArea.X<mOutputBuffer.Length;replaceArea.X++)
                            {
                                if (!Char.IsWhiteSpace(mOutputBuffer[replaceArea.X]))
                                    break;
                            }
                            ReplacementRange replaceRange=new ReplacementRange(replaceArea, new Point(commonTok.StartIndex, commonTok.StartIndex+t.Text.Length));
                            replaceRange.setChangedText(mOutputBuffer.ToString().Substring(replaceArea.X), t.Text);
                            if (!ASFormatter.validateNonWhitespaceIdentical(replaceRange.getAddedText(), replaceRange.getDeletedText()))
                            {
                                if (mReplaceMap==null)
                                    mReplaceMap=new Dictionary<Int32, ReplacementRange>();
                                mReplaceMap[replaceArea.X] = replaceRange;
                            }
                        }
                    }
                
                    onBlankLine=false;
                    blankLines=0;
                    seenCommentText=true;
                    break;
                case AS3_exParser.CHANNEL_WHITESPACE:
                    if (isFormatterOff())
                    {
                        //just spit the text out
                        mOutputBuffer.Append(t.Text);
                    }
                    else if (getFormatMode()==FORMAT_INDENT) // || isFirstTokenBeforeChangeFromFormatToIndent() || isFirstTokenBeforeChangeFromIndentToFormat())
                    {
                        //we don't care about whitespace if we are on the first token in an format-indent element; we only
                        //care about whitespace within the element
                        if (!ASFormatter.isOnlyWhitespaceOnLastLine(mOutputBuffer))// && (getFormatMode()==FORMAT_INDENT || !AntlrUtilities.isASWhitespace(mOutputBuffer.charAt(mOutputBuffer.Length-1))))
                            mOutputBuffer.Append(t.Text);
                    }
                    else
                    {
                        //do nothing; we'll add our own whitespace
                    }
                    break;
                default:
                        break;
                }
            }

    //      mFirstTokenBeforeChangeFromFormatToIndent=false;
    //      mFirstTokenBeforeChangeFromIndentToFormat=false;
    //      mFirstTokenBeforeIndentBoundary=false;
        
            //if still in non-formatting mode, then clear any whitespace that has been added to our list
            if (isFormatterOff())
                mAddedCRs.Clear();
        
            printNecessaryWS(mOutputBuffer);
        
            if (!isFormatterOff())
            {
                if ((getFormatMode()==FORMAT_ALL || getFormatMode()==FORMAT_OnlyAddCRs /*|| (getFormatMode()==FORMAT_INDENT && isFirstTokenBeforeChangeFromIndentToFormat())*/) && needToEnsureNewLine)
                {
                    if (!ASFormatter.isOnlyWhitespaceOnLastLine(mOutputBuffer))
                    {
                        insertCRIntoBuffer(mOutputBuffer);
                    }
                }

                {
                    int indentAmount=getCurrentIndent();
                    if (getIndentType(0)!=EXPRESSION_INDENT && (tok.Type==AS3_exParser.LCURLY || tok.Type==AS3_exParser.RCURLY))
                    {
                        if (!isHardIndent())
                        {
                            if (!mUseGNUBraceIndent)
                                indentAmount-=getBlockIndent();
                            else
                            {
                                IndentType indentInfo=mIndentStack[mIndentStack.Count-1];
                                if (tok.Type==AS3_exParser.LCURLY)
                                {
                                    indentInfo.mOriginalIndent=indentInfo.mAmount;
                                    indentInfo.mAmount+=getTabSize();
                                }
                                else //rcurly
                                {
                                    if (indentInfo.mOriginalIndent>=0)
                                        indentInfo.mAmount=indentInfo.mOriginalIndent;
                                    indentAmount=indentInfo.mAmount;
                                }
                            }
                        }
                    }
                    if (ASFormatter.isLineEmpty(mOutputBuffer))
                    {
                        String indentString=generateIndent(indentAmount);
                        mOutputBuffer.Append(indentString);
                    }
                }
        
                if( getFormatMode() != FORMAT_INDENT )
                {
                    if (mOutputBuffer.Length > 0 && InfoCollector.Utilities.isJavaIdentifierPart(mOutputBuffer[mOutputBuffer.Length - 1]))
                {
                    //if the start of the token is a java identifier char (any letter or number or '_')  
                    //or if the token doesn't start with whitespace, but isn't an operator either ('+=' is an operator, so we wouldn't add space, but we would add space for a string literal) 
                    if ((tok.Text.Length > 0 && InfoCollector.Utilities.isJavaIdentifierPart(tok.Text[0])) || isSymbolTokenThatShouldHaveSpaceBeforeIt(tok.Type))
                    {
                        mOutputBuffer.Append(' ');
                    }
                }
        
                //remove extra spaces before token for paren/brace/bracket case (if we're in a format mode)
                    if (tok.Text.Length==1)
                    {
                        char c = tok.Text[0];
                        if (isGroupingChar(c))
                        {
                            int i=mOutputBuffer.Length-1;
                            int spaceCount=0;
                            while (i>=0)
                            {
                                if (mOutputBuffer[i] == ' ')
                                {
                                    spaceCount++;
                                    i--;
                                }
                                else
                                    break;
                            }
                        
                            if (i>=0 && spaceCount>0) //only care if there are some spaces
                            {
                                char prevChar=mOutputBuffer[i];
                                int nestingType=determineMatchingGroupingCharType(c, prevChar);
                                if (nestingType!=Nesting_Unrelated)
                                {
                                    int amtToKeep=0;
                                    //TODO: not sure how this will work with advanced spacing settings
                                    if (!isCollapseSpaceForAdjacentParens() && nestingType!=Nesting_Opposite)
                                    {
                                        //TODO: Determine if the current context is a function call or a general
                                        //expression so that the proper 'getAdvancedSpaces' call can be made
                                        if (prevChar=='(' || c==')')
                                            amtToKeep = getAdvancedSpacesInsideParensInOtherPlaces();
                                        else if (prevChar=='{' || c=='}')
                                            amtToKeep=getAdvancedSpacesInsideObjectBraces();
                                        else if (prevChar=='[' || c==']')
                                        {
                                            amtToKeep=getAdvancedSpacesInsideArrayDeclBrackets();
                                        }
                                    }
                                    if (amtToKeep<spaceCount)
                                    {
                                        mOutputBuffer.Remove(mOutputBuffer.Length-(spaceCount-amtToKeep), mOutputBuffer.Length);
                                    }
                                }
                            }
                        }
                    }
                }
            }       
        
            //if we have a lazy indent, push it after we've processed the token
            if (mLazyIndentType>0)
            {
                if (mLazyIndentType==EXPRESSION_INDENT_NEXTITEM)
                {
                    pushExpressionIndent(determineLastLineLength(mOutputBuffer, getTabSize()));
                }
                else
                {
                    //we know it's an expression indent because that's the other possibility.  We take the current indent and add
                    //the number of tab stops based on the hanging indent setting.
                    pushIndent(mLazyIndentType);
                }
                mLazyIndentType=0;
            }
        
            if (mLazyFormatType>0)
            {
                pushFormatMode(mLazyFormatType);
                mLazyFormatType=0;
            }
        
            //special case for handling the need to lose 1 indent to support 'else-if' on the same line.  The grammar has code to 
            //pop an indent and re-add later, but it can't know whether it needs to until we get to this point and determine whether
            //the 'if' is actually on the same line with the else or not (based on else-if setting, blank lines settings, indent vs. format, etc.)
            if (mNextTokenInElseIfState)
            {
                mNextTokenInElseIfState=false;
                String newText = mOutputBuffer.ToString().Substring(currentBufferOffset);
                if (!newText.Contains("\n"))
                {
                    mElseIfNeedToLoseIndent=true;
                }
            }
        
            if (mLastCapturePosition<0)
                mLastCapturePosition=mOutputBuffer.Length;
        
            captureBraceStartPos();
        
            mOutputBuffer.Append(tok.Text);
        }
        public String print(int startIndent)
        {
            if (mSourceData.IndexOfOrdinal(mIgnoreFileProcessing)>=0)
            {
                mParseErrors=new List<Exception>();
                mParseErrors.Add(new Exception("File ignored: Ignore tag exists in file==> "+mIgnoreFileProcessing));
                return null;
            }
        
            //mOutputRange = null;
            //mReplaceRange = null;
            mAdditionalTextAddedAllPasses="";
            mRemovedTextAllPasses="";
            int maxPasses=2; //right now, there's only two passes if we are aligning equals signs or adding braces 
            int currentPasses=0;
            while (currentPasses<maxPasses)
            {
                currentPasses++;
            
                mAlreadyHaveDeclPositions=(mDeclEqualPosMap!=null);
            
                //initialize the parser state variables
                mBindablePos=(-1);
                mBindableMode=false;
                mInSingleLineFunctionMode=false;
                mAdditionalTextAdded="";
                mRemovedText="";
                mReplaceMap=null;
                mNextTokenInElseIfState=false;
                mElseIfNeedToLoseIndent=false;
                mLazyIndentType=(-1);
                mLazyFormatType=(-1);
                mFormatTypeStack=new List<Int32>();
                if (mDoFormat)
                    pushFormatMode(FORMAT_ALL);
                else
                    pushFormatMode(FORMAT_INDENT);
                mLastBindableTagName="";
            
                mExpressionWrapData=new List<WrapInfo>();
                mSourceData=InfoCollector.Utilities.convertCarriageReturnsToLineFeeds(mSourceData);
                bool addedEndCRs=false;
                if (getEndEOLs(mSourceData)<2)
                {
                    mSourceData+="\n\n";
                    addedEndCRs=true;
                }
            
                mAddBraceStack=new List<StatementBraceInfo>();
                mCompletedBraceInfos=new List<StatementBraceInfo>();
            
                mAddedCRs=new List<Int32>();
                mParseErrors=null;
                mIndentStack=new List<IndentType>();
                mIndentStack.Add(new IndentType(INITIAL_INDENT, startIndent));
                mExcludeStackCount=0;
                mLastCapturePosition=0;
                mOutputBuffer = new StringBuilder();
    //          mAlignDeclEquals=true;
                if (mAlignDeclEquals && !mIsKeepingExcessDeclWhitespace)// && currentPasses==0)
                {
                    mCurrentDeclEqualContext=new EqualContext(null, 0);
                    mRootDeclEqualContext=mCurrentDeclEqualContext;
                }
    //          else
    //              mCurrentDeclEqualContext=null;
                try
                {
        //          if (mIsCompleteFile)
                        mWorkingSource=mSourceData;
        //          else
        //              mWorkingSource="class DummyClassWrapper {"+mSourceData+ "}";
                    
                    ANTLRStringStream stream=new ANTLRStringStream(mWorkingSource);
                    AS3_exLexer l2=new AS3_exLexer(stream);
                    mRawTokens=new CommonTokenStream(l2);
                    AS3_exParser p2=new AS3_exParser(this, mRawTokens);
                
                    AS3_exParser.fileContents_return retVal=p2.fileContents();
                
                    //handle any remaining hidden tokens
                    IToken t = new CommonToken(AS3_exParser.EOF, "");
                    t.TokenIndex = mRawTokens.Count;
                    emit(t);
                
                    //process braces that may need to be added or deleted
                    
                        List<EditItem> editItems=new List<EditItem>();
                        foreach (StatementBraceInfo info in mCompletedBraceInfos) 
                        {
                            if (info.isBracesCurrentlyExist())
                            {
                                if (isRemoveBraces(info))
                                {
                                    int startBracePos = mOutputBuffer.ToString().IndexOf('{', info.getStartBracePos());
                                    int endBracePos = mOutputBuffer.ToString().LastIndexOf('}', info.getEndBracePos());
                                    int endBracePosInSource=mSourceData.LastIndexOf('}', info.getOriginalDocEndPosition());
                                    editItems.Add(new DeleteItem(startBracePos, 1, info.getOriginalDocStartPosition()));
                                    editItems.Add(new DeleteItem(endBracePos, 1, endBracePosInSource));
                                
                                    //if brace is followed by nothing but a carriage return, return the next
                                    //cr as well.
                                    int nextCR = mOutputBuffer.ToString().IndexOf('\n', startBracePos + 1);
                                    if (nextCR>=0)
                                    {
                                        String nextChars = mOutputBuffer.ToString().Substring(startBracePos + 1, nextCR - (startBracePos + 1)).Trim();
                                        if (nextChars.Length==0)
                                        {
                                            editItems.Add(new DeleteItem(nextCR, 1, -1));
                                        }
                                    }
                                    nextCR = mOutputBuffer.ToString().IndexOf('\n', endBracePos + 1);
                                    if (nextCR>=0)
                                    {
                                        String nextChars = mOutputBuffer.ToString().Substring(endBracePos + 1, nextCR - (endBracePos + 1)).Trim();
                                        if (nextChars.Length==0)
                                        {
                                            editItems.Add(new DeleteItem(nextCR, 1, -1));
                                        }
                                    }                               
                                }
                            }
                            else
                            {
                                if (isAddBraces(info))
                                {
                                    editItems.Add(new InsertItem(info.getStartBracePos(), "{", info.getOriginalDocStartPosition()));
                                    editItems.Add(new InsertItem(info.getEndBracePos(), "}", info.getOriginalDocEndPosition()));
                                }
                            }
                        }

                        editItems.Sort((o1, o2) => o1.getLocation() - o2.getLocation());

                        /*
                        Collections.sort(editItems, new IComparer<EditItem>() 
                        {
                            public int compare(EditItem o1, EditItem o2) {
                                return o1.mLocation-o2.mLocation;
                            }
                        });
                        */

                        if (mReplaceMap==null)
                            mReplaceMap=new Dictionary<Int32, ReplacementRange>();

                        int addedChars=0;
                        for (int j=0;j<editItems.Count;j++)
                        {
                            EditItem item=editItems[j];
                            if (item is InsertItem)
                            {
                                InsertItem iItem=(InsertItem)item;
                                mOutputBuffer.Insert(item.getLocation()+addedChars, iItem.getData());

                                ReplacementRange existingRange=mReplaceMap[iItem.getOriginalInsertLocation()];
                                if (existingRange!=null)
                                {
                                    //this can happen if two close braces are added at the same point in the file.  As such,
                                    //I'm handling this special case.
                                    existingRange.setChangedText(existingRange.getAddedText()+iItem.getData(), existingRange.getDeletedText());
                                    existingRange.mRangeInFormattedDoc.Y += iItem.getData().Length;
                                }
                                else
                                {
                                    ReplacementRange range=new ReplacementRange(new Point(item.getLocation()+addedChars, item.getLocation()+addedChars+iItem.getData().Length), new Point(iItem.getOriginalInsertLocation(),iItem.getOriginalInsertLocation()));
                                    mReplaceMap[iItem.getOriginalInsertLocation()] = range;
                                    range.setChangedText(iItem.getData(), "");
                                }
                                addedChars+=iItem.getData().Length;
                                mAdditionalTextAdded+=iItem.getData();
                                mAdditionalTextAddedAllPasses+=iItem.getData();

                            }
                            else
                            {
                                //add replacemap item, but only if non-whitespace is being deleted
                                //TODO: what if a brace is added and deleted at same location? Will that break the merging code?
                                DeleteItem dItem=(DeleteItem)item;
                                Int32 start = dItem.getLocation() + addedChars;
                                Int32 end = dItem.getLocation() + dItem.getLength() + addedChars;
                                String removedData = mOutputBuffer.ToString().Substring(start, end - start);
                                if (dItem.getOriginalDeleteLocation()>=0)
                                {
                                    ReplacementRange range=new ReplacementRange(new Point(item.getLocation()+addedChars, item.getLocation()+addedChars), new Point(dItem.getOriginalDeleteLocation(),dItem.getOriginalDeleteLocation()+dItem.getLength()));
                                    mReplaceMap[dItem.getOriginalDeleteLocation()] = range;
                                    range.setChangedText("", removedData);
                                }
                                mOutputBuffer.Remove(dItem.getLocation()+addedChars, dItem.getLocation()+dItem.getLength()+addedChars);
                                addedChars-=removedData.Length;
                                mRemovedText+=removedData;
                                mRemovedTextAllPasses+=removedData;
                            
                            }
                        }
                    
                
                    String resultText=mOutputBuffer.ToString();
                    
                    mParseErrors=p2.getParseErrors();
                    if (mParseErrors!=null || resultText==null)
                        return null;
    
                    String oldString=mWorkingSource+mAdditionalTextAdded;
                    if (mAdditionalTextAdded.Length==0 && mRemovedText.Length==0 && ASFormatter.validateNonWhitespaceIdentical(resultText, mWorkingSource) || ((mAdditionalTextAdded.Length>0 || (mRemovedText.Length>0)) && ASFormatter.validateNonWhitespaceCharCounts(resultText+mRemovedText, oldString)))
                    {
                        //trim extra newlines at the end of result text
                        if (mDoFormat)
                        {
                            int oldEndLines=getEndEOLs(mWorkingSource)-(addedEndCRs ? 2 : 0); //I may have added two above
                            int newEndLines=getEndEOLs(resultText);
                            if (newEndLines>oldEndLines)
                            {
                                resultText=resultText.Substring(0, resultText.Length-(newEndLines-oldEndLines));
                                if (mOutputRange!=null && mOutputRange.Y>resultText.Length)
                                {
                                    mOutputRange.Y = resultText.Length;
                                }
                            }
                        }
                    
                        //if we are trying to capture the output range but haven't captured it yet
                        if (mOutputRange != null && mOutputRange.Y < 0)
                        {
                            mOutputRange.Y = resultText.Length;
                            mReplaceRange.Y = mWorkingSource.Length;
                            if (mDoFormat && addedEndCRs)
                                mReplaceRange.Y -= "\n\n".Length;
                        }
                    
                        if (mRootDeclEqualContext!=null)
                        {
                            mDeclEqualPosMap=new Dictionary<String, Int32>();
                            mRootDeclEqualContext.fillMap(mDeclEqualPosMap);
                        }
                    
                        //if multiple passes are allowed and we would benefit from one and this is not a partial format
                        if (mAllowMultiplePasses && needAnotherPass() && mOutputRange==null)
                        {
                            mSourceData=resultText;
                            continue;
                        }
                        return resultText;
                    }
                    else
                    {
                        mParseErrors=new List<Exception>();
                        mParseErrors.Add(new Exception("Internal error: Formatted text doesn't match source. "+resultText+"!="+mWorkingSource));
                    }
                }
                finally
                {
                }
                return null;
            }
        
            //return what I have in case the multiple
            //passes algorithm gets confused
            return mSourceData;
        }