/// \file
/// Defines the implementation of the common node stream the default
/// tree node stream used by ANTLR.
///

// [The "BSD licence"]
// Copyright (c) 2005-2009 Jim Idle, Temporal Wave LLC
// http://www.temporal-wave.com
// http://www.linkedin.com/in/jimidle
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
// 3. The name of the author may not be used to endorse or promote products
//    derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include    <antlr3commontreenodestream.h>

#ifdef  ANTLR3_WINDOWS
#pragma warning( disable : 4100 )
#endif

// COMMON TREE STREAM API
//
static  void                                            addNavigationNode                       (pANTLR3_COMMON_TREE_NODE_STREAM ctns, ANTLR3_UINT32 ttype);
static  ANTLR3_BOOLEAN                          hasUniqueNavigationNodes        (pANTLR3_COMMON_TREE_NODE_STREAM ctns);
static  pANTLR3_BASE_TREE                       newDownNode                                     (pANTLR3_COMMON_TREE_NODE_STREAM ctns);
static  pANTLR3_BASE_TREE                       newUpNode                                       (pANTLR3_COMMON_TREE_NODE_STREAM ctns);
static  void                                            reset                                           (pANTLR3_COMMON_TREE_NODE_STREAM ctns);
static  void                                            push                                            (pANTLR3_COMMON_TREE_NODE_STREAM ctns, ANTLR3_INT32 index);
static  ANTLR3_INT32                            pop                                                     (pANTLR3_COMMON_TREE_NODE_STREAM ctns);
//static        ANTLR3_INT32                            index                                           (pANTLR3_COMMON_TREE_NODE_STREAM ctns);
static  ANTLR3_UINT32                           getLookaheadSize                        (pANTLR3_COMMON_TREE_NODE_STREAM ctns);
// TREE NODE STREAM API
//
static  pANTLR3_BASE_TREE_ADAPTOR   getTreeAdaptor                              (pANTLR3_TREE_NODE_STREAM tns);
static  pANTLR3_BASE_TREE                       getTreeSource                           (pANTLR3_TREE_NODE_STREAM tns);
static  pANTLR3_BASE_TREE                       _LT                                                     (pANTLR3_TREE_NODE_STREAM tns, ANTLR3_INT32 k);
static  pANTLR3_BASE_TREE                       get                                                     (pANTLR3_TREE_NODE_STREAM tns, ANTLR3_INT32 k);
static  void                                            setUniqueNavigationNodes        (pANTLR3_TREE_NODE_STREAM tns, ANTLR3_BOOLEAN uniqueNavigationNodes);
static  pANTLR3_STRING                          toString                                        (pANTLR3_TREE_NODE_STREAM tns);
static  pANTLR3_STRING                          toStringSS                                      (pANTLR3_TREE_NODE_STREAM tns, pANTLR3_BASE_TREE start, pANTLR3_BASE_TREE stop);
static  void                                            toStringWork                            (pANTLR3_TREE_NODE_STREAM tns, pANTLR3_BASE_TREE start, pANTLR3_BASE_TREE stop, pANTLR3_STRING buf);
static  void                                            replaceChildren                         (pANTLR3_TREE_NODE_STREAM tns, pANTLR3_BASE_TREE parent, ANTLR3_INT32 startChildIndex, ANTLR3_INT32 stopChildIndex, pANTLR3_BASE_TREE t);

// INT STREAM API
//
static  void                                            consume                                         (pANTLR3_INT_STREAM is);
static  ANTLR3_MARKER                           tindex                                          (pANTLR3_INT_STREAM is);
static  ANTLR3_UINT32                           _LA                                                     (pANTLR3_INT_STREAM is, ANTLR3_INT32 i);
static  ANTLR3_MARKER                           mark                                            (pANTLR3_INT_STREAM is);
static  void                                            release                                         (pANTLR3_INT_STREAM is, ANTLR3_MARKER marker);
static  void                                            rewindMark                                      (pANTLR3_INT_STREAM is, ANTLR3_MARKER marker);
static  void                                            rewindLast                                      (pANTLR3_INT_STREAM is);
static  void                                            seek                                            (pANTLR3_INT_STREAM is, ANTLR3_MARKER index);
static  ANTLR3_UINT32                           size                                            (pANTLR3_INT_STREAM is);


// Helper functions
//
static  void                                            fillBuffer                                      (pANTLR3_COMMON_TREE_NODE_STREAM ctns, pANTLR3_BASE_TREE t);
static  void                                            fillBufferRoot                          (pANTLR3_COMMON_TREE_NODE_STREAM ctns);

// Constructors
//
static  void                                            antlr3TreeNodeStreamFree                        (pANTLR3_TREE_NODE_STREAM tns);
static  void                                            antlr3CommonTreeNodeStreamFree          (pANTLR3_COMMON_TREE_NODE_STREAM ctns);

ANTLR3_API pANTLR3_TREE_NODE_STREAM
antlr3TreeNodeStreamNew()
{
    pANTLR3_TREE_NODE_STREAM stream;

    // Memory for the interface structure
    //
    stream  = (pANTLR3_TREE_NODE_STREAM) ANTLR3_CALLOC(1, sizeof(ANTLR3_TREE_NODE_STREAM));

    if  (stream == NULL)
    {
                return  NULL;
    }

    // Install basic API
    //
        stream->replaceChildren = replaceChildren;
    stream->free                        = antlr3TreeNodeStreamFree;

    return stream;
}

static void
antlr3TreeNodeStreamFree(pANTLR3_TREE_NODE_STREAM stream)
{
    ANTLR3_FREE(stream);
}

ANTLR3_API pANTLR3_COMMON_TREE_NODE_STREAM
antlr3CommonTreeNodeStreamNewTree(pANTLR3_BASE_TREE tree, ANTLR3_UINT32 hint)
{
        pANTLR3_COMMON_TREE_NODE_STREAM stream;

        stream = antlr3CommonTreeNodeStreamNew(tree->strFactory, hint);

        if      (stream == NULL)
        {
                return  NULL;
        }
        stream->root    = tree;

        return stream;
}

ANTLR3_API pANTLR3_COMMON_TREE_NODE_STREAM
antlr3CommonTreeNodeStreamNewStream(pANTLR3_COMMON_TREE_NODE_STREAM inStream)
{
        pANTLR3_COMMON_TREE_NODE_STREAM stream;

        // Memory for the interface structure
        //
        stream  = (pANTLR3_COMMON_TREE_NODE_STREAM) ANTLR3_CALLOC(1, sizeof(ANTLR3_COMMON_TREE_NODE_STREAM));

        if      (stream == NULL)
        {
                return  NULL;
        }

        // Copy in all the reusable parts of the originating stream and create new
        // pieces where necessary.
        //

        // String factory for tree walker
        //
        stream->stringFactory           = inStream->stringFactory;

        // Create an adaptor for the common tree node stream
        //
        stream->adaptor                         = inStream->adaptor;

        // Create space for the tree node stream interface
        //
        stream->tnstream            = antlr3TreeNodeStreamNew();

        if      (stream->tnstream == NULL)
        {
                stream->free                            (stream);

                return  NULL;
        }

        // Create space for the INT_STREAM interface
        //
        stream->tnstream->istream                   =  antlr3IntStreamNew();

        if      (stream->tnstream->istream == NULL)
        {
                stream->tnstream->free          (stream->tnstream);
                stream->free                            (stream);

                return  NULL;
        }

        // Install the common tree node stream API
        //
        stream->addNavigationNode                   =  addNavigationNode;
        stream->hasUniqueNavigationNodes    =  hasUniqueNavigationNodes;
        stream->newDownNode                                     =  newDownNode;
        stream->newUpNode                                       =  newUpNode;
        stream->reset                                           =  reset;
        stream->push                                            =  push;
        stream->pop                                                     =  pop;
        stream->getLookaheadSize                        =  getLookaheadSize;

        stream->free                        =  antlr3CommonTreeNodeStreamFree;

        // Install the tree node stream API
        //
        stream->tnstream->getTreeAdaptor                        =  getTreeAdaptor;
        stream->tnstream->getTreeSource                         =  getTreeSource;
        stream->tnstream->_LT                                           =  _LT;
        stream->tnstream->setUniqueNavigationNodes      =  setUniqueNavigationNodes;
        stream->tnstream->toString                                      =  toString;
        stream->tnstream->toStringSS                            =  toStringSS;
        stream->tnstream->toStringWork                          =  toStringWork;
        stream->tnstream->get                                           =  get;

        // Install INT_STREAM interface
        //
        stream->tnstream->istream->consume          =  consume;
        stream->tnstream->istream->index            =  tindex;
        stream->tnstream->istream->_LA                  =  _LA;
        stream->tnstream->istream->mark                 =  mark;
        stream->tnstream->istream->release          =  release;
        stream->tnstream->istream->rewind           =  rewindMark;
        stream->tnstream->istream->rewindLast   =  rewindLast;
        stream->tnstream->istream->seek                 =  seek;
        stream->tnstream->istream->size                 =  size;

        // Initialize data elements of INT stream
        //
        stream->tnstream->istream->type                 = ANTLR3_COMMONTREENODE;
        stream->tnstream->istream->super            =  (stream->tnstream);

        // Initialize data elements of TREE stream
        //
        stream->tnstream->ctns =  stream;

        // Initialize data elements of the COMMON TREE NODE stream
        //
        stream->super                                   = NULL;
        stream->uniqueNavigationNodes   = ANTLR3_FALSE;
        stream->markers                                 = NULL;
        stream->nodeStack                               = inStream->nodeStack;

        // Create the node list map
        //
        stream->nodes   = antlr3VectorNew(DEFAULT_INITIAL_BUFFER_SIZE);
        stream->p               = -1;

        // Install the navigation nodes
        //

        // Install the navigation nodes
        //
        antlr3SetCTAPI(&(stream->UP));
        antlr3SetCTAPI(&(stream->DOWN));
        antlr3SetCTAPI(&(stream->EOF_NODE));
        antlr3SetCTAPI(&(stream->INVALID_NODE));

        stream->UP.token                                                = inStream->UP.token;
        inStream->UP.token->strFactory                  = stream->stringFactory;
        stream->DOWN.token                                              = inStream->DOWN.token;
        inStream->DOWN.token->strFactory                = stream->stringFactory;
        stream->EOF_NODE.token                                  = inStream->EOF_NODE.token;
        inStream->EOF_NODE.token->strFactory    = stream->stringFactory;
        stream->INVALID_NODE.token                              = inStream->INVALID_NODE.token;
        inStream->INVALID_NODE.token->strFactory= stream->stringFactory;

        // Reuse the root tree of the originating stream
        //
        stream->root            = inStream->root;

        // Signal that this is a rewriting stream so we don't
        // free the originating tree. Anything that we rewrite or
        // duplicate here will be done through the adaptor or
        // the original tree factory.
        //
        stream->isRewriter      = ANTLR3_TRUE;
        return stream;
}

ANTLR3_API pANTLR3_COMMON_TREE_NODE_STREAM
antlr3CommonTreeNodeStreamNew(pANTLR3_STRING_FACTORY strFactory, ANTLR3_UINT32 hint)
{
        pANTLR3_COMMON_TREE_NODE_STREAM stream;
        pANTLR3_COMMON_TOKEN                    token;

        // Memory for the interface structure
        //
        stream  = (pANTLR3_COMMON_TREE_NODE_STREAM) ANTLR3_CALLOC(1, sizeof(ANTLR3_COMMON_TREE_NODE_STREAM));

        if      (stream == NULL)
        {
                return  NULL;
        }

        // String factory for tree walker
        //
        stream->stringFactory           = strFactory;

        // Create an adaptor for the common tree node stream
        //
        stream->adaptor                         = ANTLR3_TREE_ADAPTORNew(strFactory);

        if      (stream->adaptor == NULL)
        {
                stream->free(stream);
                return  NULL;
        }

        // Create space for the tree node stream interface
        //
        stream->tnstream            = antlr3TreeNodeStreamNew();

        if      (stream->tnstream == NULL)
        {
                stream->adaptor->free           (stream->adaptor);
                stream->free                            (stream);

                return  NULL;
        }

        // Create space for the INT_STREAM interface
        //
        stream->tnstream->istream                   =  antlr3IntStreamNew();

        if      (stream->tnstream->istream == NULL)
        {
                stream->adaptor->free           (stream->adaptor);
                stream->tnstream->free          (stream->tnstream);
                stream->free                            (stream);

                return  NULL;
        }

        // Install the common tree node stream API
        //
        stream->addNavigationNode                   =  addNavigationNode;
        stream->hasUniqueNavigationNodes    =  hasUniqueNavigationNodes;
        stream->newDownNode                                     =  newDownNode;
        stream->newUpNode                                       =  newUpNode;
        stream->reset                                           =  reset;
        stream->push                                            =  push;
        stream->pop                                                     =  pop;

        stream->free                        =  antlr3CommonTreeNodeStreamFree;

        // Install the tree node stream API
        //
        stream->tnstream->getTreeAdaptor                        =  getTreeAdaptor;
        stream->tnstream->getTreeSource                         =  getTreeSource;
        stream->tnstream->_LT                                           =  _LT;
        stream->tnstream->setUniqueNavigationNodes      =  setUniqueNavigationNodes;
        stream->tnstream->toString                                      =  toString;
        stream->tnstream->toStringSS                            =  toStringSS;
        stream->tnstream->toStringWork                          =  toStringWork;
        stream->tnstream->get                                           =  get;

        // Install INT_STREAM interface
        //
        stream->tnstream->istream->consume          =  consume;
        stream->tnstream->istream->index            =  tindex;
        stream->tnstream->istream->_LA                  =  _LA;
        stream->tnstream->istream->mark                 =  mark;
        stream->tnstream->istream->release          =  release;
        stream->tnstream->istream->rewind           =  rewindMark;
        stream->tnstream->istream->rewindLast   =  rewindLast;
        stream->tnstream->istream->seek                 =  seek;
        stream->tnstream->istream->size                 =  size;

        // Initialize data elements of INT stream
        //
        stream->tnstream->istream->type                 = ANTLR3_COMMONTREENODE;
        stream->tnstream->istream->super            =  (stream->tnstream);

        // Initialize data elements of TREE stream
        //
        stream->tnstream->ctns =  stream;

        // Initialize data elements of the COMMON TREE NODE stream
        //
        stream->super                                   = NULL;
        stream->uniqueNavigationNodes   = ANTLR3_FALSE;
        stream->markers                                 = NULL;
        stream->nodeStack                               = antlr3StackNew(INITIAL_CALL_STACK_SIZE);

        // Create the node list map
        //
        if      (hint == 0)
        {
                hint = DEFAULT_INITIAL_BUFFER_SIZE;
        }
        stream->nodes   = antlr3VectorNew(hint);
        stream->p               = -1;

        // Install the navigation nodes
        //
        antlr3SetCTAPI(&(stream->UP));
        antlr3SetCTAPI(&(stream->DOWN));
        antlr3SetCTAPI(&(stream->EOF_NODE));
        antlr3SetCTAPI(&(stream->INVALID_NODE));

        token                                           = antlr3CommonTokenNew(ANTLR3_TOKEN_UP);
        token->strFactory                       = strFactory;
        token->textState                        = ANTLR3_TEXT_CHARP;
        token->tokText.chars            = (pANTLR3_UCHAR)"UP";
        stream->UP.token                        = token;

        token                                           = antlr3CommonTokenNew(ANTLR3_TOKEN_DOWN);
        token->strFactory                       = strFactory;
        token->textState                        = ANTLR3_TEXT_CHARP;
        token->tokText.chars            = (pANTLR3_UCHAR)"DOWN";
        stream->DOWN.token                      = token;

        token                                           = antlr3CommonTokenNew(ANTLR3_TOKEN_EOF);
        token->strFactory                       = strFactory;
        token->textState                        = ANTLR3_TEXT_CHARP;
        token->tokText.chars            = (pANTLR3_UCHAR)"EOF";
        stream->EOF_NODE.token          = token;

        token                                           = antlr3CommonTokenNew(ANTLR3_TOKEN_INVALID);
        token->strFactory                       = strFactory;
        token->textState                        = ANTLR3_TEXT_CHARP;
        token->tokText.chars            = (pANTLR3_UCHAR)"INVALID";
        stream->INVALID_NODE.token      = token;


        return  stream;
}

/// Free up any resources that belong to this common tree node stream.
///
static  void                        antlr3CommonTreeNodeStreamFree  (pANTLR3_COMMON_TREE_NODE_STREAM ctns)
{

        // If this is a rewrting stream, then certain resources
        // belong to the originating node stream and we do not
        // free them here.
        //
        if      (ctns->isRewriter != ANTLR3_TRUE)
        {
                ctns->adaptor                   ->free  (ctns->adaptor);

                if      (ctns->nodeStack != NULL)
                {
                        ctns->nodeStack->free(ctns->nodeStack);
                }

                ANTLR3_FREE(ctns->INVALID_NODE.token);
                ANTLR3_FREE(ctns->EOF_NODE.token);
                ANTLR3_FREE(ctns->DOWN.token);
                ANTLR3_FREE(ctns->UP.token);
        }

        if      (ctns->nodes != NULL)
        {
                ctns->nodes                     ->free  (ctns->nodes);
        }
        ctns->tnstream->istream ->free  (ctns->tnstream->istream);
    ctns->tnstream                      ->free  (ctns->tnstream);


    ANTLR3_FREE(ctns);
}

// ------------------------------------------------------------------------------
// Local helpers
//

/// Walk and fill the tree node buffer from the root tree
///
static void
fillBufferRoot(pANTLR3_COMMON_TREE_NODE_STREAM ctns)
{
        // Call the generic buffer routine with the root as the
        // argument
        //
        fillBuffer(ctns, ctns->root);
        ctns->p = 0;                                    // Indicate we are at buffer start
}

/// Walk tree with depth-first-search and fill nodes buffer.
/// Don't add in DOWN, UP nodes if the supplied tree is a list (t is isNilNode)
// such as the root tree is.
///
static void
fillBuffer(pANTLR3_COMMON_TREE_NODE_STREAM ctns, pANTLR3_BASE_TREE t)
{
        ANTLR3_BOOLEAN  nilNode;
        ANTLR3_UINT32   nCount;
        ANTLR3_UINT32   c;

        nilNode = ctns->adaptor->isNilNode(ctns->adaptor, t);

        // If the supplied node is not a nil (list) node then we
        // add in the node itself to the vector
        //
        if      (nilNode == ANTLR3_FALSE)
        {
                ctns->nodes->add(ctns->nodes, t, NULL);
        }

        // Only add a DOWN node if the tree is not a nil tree and
        // the tree does have children.
        //
        nCount = t->getChildCount(t);

        if      (nilNode == ANTLR3_FALSE && nCount>0)
        {
                ctns->addNavigationNode(ctns, ANTLR3_TOKEN_DOWN);
        }

        // We always add any children the tree contains, which is
        // a recursive call to this function, which will cause similar
        // recursion and implement a depth first addition
        //
        for     (c = 0; c < nCount; c++)
        {
                fillBuffer(ctns, (pANTLR3_BASE_TREE)ctns->adaptor->getChild(ctns->adaptor, t, c));
        }

        // If the tree had children and was not a nil (list) node, then we
        // we need to add an UP node here to match the DOWN node
        //
        if      (nilNode == ANTLR3_FALSE && nCount > 0)
        {
                ctns->addNavigationNode(ctns, ANTLR3_TOKEN_UP);
        }
}


// ------------------------------------------------------------------------------
// Interface functions
//

/// Reset the input stream to the start of the input nodes.
///
static  void
reset       (pANTLR3_COMMON_TREE_NODE_STREAM ctns)
{
        if      (ctns->p != -1)
        {
                ctns->p                                                                 = 0;
        }
        ctns->tnstream->istream->lastMarker             = 0;


        // Free and reset the node stack only if this is not
        // a rewriter, which is going to reuse the originating
        // node streams node stack
        //
        if  (ctns->isRewriter != ANTLR3_TRUE)
    {
                if      (ctns->nodeStack != NULL)
                {
                        ctns->nodeStack->free(ctns->nodeStack);
                        ctns->nodeStack = antlr3StackNew(INITIAL_CALL_STACK_SIZE);
                }
        }
}


static pANTLR3_BASE_TREE
LB(pANTLR3_TREE_NODE_STREAM tns, ANTLR3_INT32 k)
{
        if      ( k==0)
        {
                return  &(tns->ctns->INVALID_NODE.baseTree);
        }

        if      ( (tns->ctns->p - k) < 0)
        {
                return  &(tns->ctns->INVALID_NODE.baseTree);
        }

        return (pANTLR3_BASE_TREE)tns->ctns->nodes->get(tns->ctns->nodes, tns->ctns->p - k);
}

/// Get tree node at current input pointer + i ahead where i=1 is next node.
/// i<0 indicates nodes in the past.  So -1 is previous node and -2 is
/// two nodes ago. LT(0) is undefined.  For i>=n, return null.
/// Return null for LT(0) and any index that results in an absolute address
/// that is negative.
///
/// This is analogous to the _LT() method of the TokenStream, but this
/// returns a tree node instead of a token.  Makes code gen identical
/// for both parser and tree grammars. :)
///
static  pANTLR3_BASE_TREE
_LT         (pANTLR3_TREE_NODE_STREAM tns, ANTLR3_INT32 k)
{
        if      (tns->ctns->p == -1)
        {
                fillBufferRoot(tns->ctns);
        }

        if      (k < 0)
        {
                return LB(tns, -k);
        }
        else if (k == 0)
        {
                return  &(tns->ctns->INVALID_NODE.baseTree);
        }

        // k was a legitimate request,
        //
        if      (( tns->ctns->p + k - 1) >= (ANTLR3_INT32)(tns->ctns->nodes->count))
        {
                return &(tns->ctns->EOF_NODE.baseTree);
        }

        return  (pANTLR3_BASE_TREE)tns->ctns->nodes->get(tns->ctns->nodes, tns->ctns->p + k - 1);
}

/// Where is this stream pulling nodes from?  This is not the name, but
/// the object that provides node objects.
///
static  pANTLR3_BASE_TREE
getTreeSource   (pANTLR3_TREE_NODE_STREAM tns)
{
    return  tns->ctns->root;
}

/// Consume the next node from the input stream
///
static  void
consume (pANTLR3_INT_STREAM is)
{
    pANTLR3_TREE_NODE_STREAM            tns;
    pANTLR3_COMMON_TREE_NODE_STREAM     ctns;

    tns     = (pANTLR3_TREE_NODE_STREAM)(is->super);
    ctns    = tns->ctns;

        if      (ctns->p == -1)
        {
                fillBufferRoot(ctns);
        }
        ctns->p++;
}

static  ANTLR3_UINT32
_LA         (pANTLR3_INT_STREAM is, ANTLR3_INT32 i)
{
        pANTLR3_TREE_NODE_STREAM                tns;
        pANTLR3_BASE_TREE                               t;

        tns         = (pANTLR3_TREE_NODE_STREAM)(is->super);

        // Ask LT for the 'token' at that position
        //
        t = tns->_LT(tns, i);

        if      (t == NULL)
        {
                return  ANTLR3_TOKEN_INVALID;
        }

        // Token node was there so return the type of it
        //
        return  t->getType(t);
}

/// Mark the state of the input stream so that we can come back to it
/// after a syntactic predicate and so on.
///
static  ANTLR3_MARKER
mark    (pANTLR3_INT_STREAM is)
{
        pANTLR3_TREE_NODE_STREAM                tns;
        pANTLR3_COMMON_TREE_NODE_STREAM ctns;

        tns         = (pANTLR3_TREE_NODE_STREAM)(is->super);
        ctns    = tns->ctns;

        if      (tns->ctns->p == -1)
        {
                fillBufferRoot(tns->ctns);
        }

        // Return the current mark point
        //
        ctns->tnstream->istream->lastMarker = ctns->tnstream->istream->index(ctns->tnstream->istream);

        return ctns->tnstream->istream->lastMarker;
}

static  void
release (pANTLR3_INT_STREAM is, ANTLR3_MARKER marker)
{
}

/// Rewind the current state of the tree walk to the state it
/// was in when mark() was called and it returned marker.  Also,
/// wipe out the lookahead which will force reloading a few nodes
/// but it is better than making a copy of the lookahead buffer
/// upon mark().
///
static  void
rewindMark          (pANTLR3_INT_STREAM is, ANTLR3_MARKER marker)
{
        is->seek(is, marker);
}

static  void
rewindLast      (pANTLR3_INT_STREAM is)
{
   is->seek(is, is->lastMarker);
}

/// consume() ahead until we hit index.  Can't just jump ahead--must
/// spit out the navigation nodes.
///
static  void
seek    (pANTLR3_INT_STREAM is, ANTLR3_MARKER index)
{
    pANTLR3_TREE_NODE_STREAM            tns;
    pANTLR3_COMMON_TREE_NODE_STREAM     ctns;

    tns     = (pANTLR3_TREE_NODE_STREAM)(is->super);
    ctns    = tns->ctns;

        ctns->p = ANTLR3_UINT32_CAST(index);
}

static  ANTLR3_MARKER
tindex  (pANTLR3_INT_STREAM is)
{
    pANTLR3_TREE_NODE_STREAM            tns;
    pANTLR3_COMMON_TREE_NODE_STREAM     ctns;

    tns     = (pANTLR3_TREE_NODE_STREAM)(is->super);
    ctns    = tns->ctns;

        return (ANTLR3_MARKER)(ctns->p);
}

/// Expensive to compute the size of the whole tree while parsing.
/// This method only returns how much input has been seen so far.  So
/// after parsing it returns true size.
///
static  ANTLR3_UINT32
size    (pANTLR3_INT_STREAM is)
{
    pANTLR3_TREE_NODE_STREAM            tns;
    pANTLR3_COMMON_TREE_NODE_STREAM     ctns;

    tns     = (pANTLR3_TREE_NODE_STREAM)(is->super);
    ctns    = tns->ctns;

        if      (ctns->p == -1)
        {
                fillBufferRoot(ctns);
        }

        return ctns->nodes->size(ctns->nodes);
}

/// As we flatten the tree, we use UP, DOWN nodes to represent
/// the tree structure.  When debugging we need unique nodes
/// so instantiate new ones when uniqueNavigationNodes is true.
///
static  void
addNavigationNode           (pANTLR3_COMMON_TREE_NODE_STREAM ctns, ANTLR3_UINT32 ttype)
{
        pANTLR3_BASE_TREE           node;

        node = NULL;

        if      (ttype == ANTLR3_TOKEN_DOWN)
        {
                if  (ctns->hasUniqueNavigationNodes(ctns) == ANTLR3_TRUE)
                {
                        node    = ctns->newDownNode(ctns);
                }
                else
                {
                        node    = &(ctns->DOWN.baseTree);
                }
        }
        else
        {
                if  (ctns->hasUniqueNavigationNodes(ctns) == ANTLR3_TRUE)
                {
                        node    = ctns->newUpNode(ctns);
                }
                else
                {
                        node    = &(ctns->UP.baseTree);
                }
        }

        // Now add the node we decided upon.
        //
        ctns->nodes->add(ctns->nodes, node, NULL);
}


static  pANTLR3_BASE_TREE_ADAPTOR
getTreeAdaptor  (pANTLR3_TREE_NODE_STREAM tns)
{
    return  tns->ctns->adaptor;
}

static  ANTLR3_BOOLEAN
hasUniqueNavigationNodes            (pANTLR3_COMMON_TREE_NODE_STREAM ctns)
{
    return  ctns->uniqueNavigationNodes;
}

static  void
setUniqueNavigationNodes            (pANTLR3_TREE_NODE_STREAM tns, ANTLR3_BOOLEAN uniqueNavigationNodes)
{
    tns->ctns->uniqueNavigationNodes = uniqueNavigationNodes;
}


/// Print out the entire tree including DOWN/UP nodes.  Uses
/// a recursive walk.  Mostly useful for testing as it yields
/// the token types not text.
///
static  pANTLR3_STRING
toString            (pANTLR3_TREE_NODE_STREAM tns)
{

    return  tns->toStringSS(tns, tns->ctns->root, NULL);
}

static  pANTLR3_STRING
toStringSS          (pANTLR3_TREE_NODE_STREAM tns, pANTLR3_BASE_TREE start, pANTLR3_BASE_TREE stop)
{
    pANTLR3_STRING  buf;

    buf = tns->ctns->stringFactory->newRaw(tns->ctns->stringFactory);

    tns->toStringWork(tns, start, stop, buf);

    return  buf;
}

static  void
toStringWork    (pANTLR3_TREE_NODE_STREAM tns, pANTLR3_BASE_TREE p, pANTLR3_BASE_TREE stop, pANTLR3_STRING buf)
{

        ANTLR3_UINT32   n;
        ANTLR3_UINT32   c;

        if      (!p->isNilNode(p) )
        {
                pANTLR3_STRING  text;

                text    = p->toString(p);

                if  (text == NULL)
                {
                        text = tns->ctns->stringFactory->newRaw(tns->ctns->stringFactory);

                        text->addc      (text, ' ');
                        text->addi      (text, p->getType(p));
                }

                buf->appendS(buf, text);
        }

        if      (p == stop)
        {
                return;         /* Finished */
        }

        n = p->getChildCount(p);

        if      (n > 0 && ! p->isNilNode(p) )
        {
                buf->addc   (buf, ' ');
                buf->addi   (buf, ANTLR3_TOKEN_DOWN);
        }

        for     (c = 0; c<n ; c++)
        {
                pANTLR3_BASE_TREE   child;

                child = (pANTLR3_BASE_TREE)p->getChild(p, c);
                tns->toStringWork(tns, child, stop, buf);
        }

        if      (n > 0 && ! p->isNilNode(p) )
        {
                buf->addc   (buf, ' ');
                buf->addi   (buf, ANTLR3_TOKEN_UP);
        }
}

static  ANTLR3_UINT32
getLookaheadSize        (pANTLR3_COMMON_TREE_NODE_STREAM ctns)
{
    return      ctns->tail < ctns->head
            ?   (ctns->lookAheadLength - ctns->head + ctns->tail)
            :   (ctns->tail - ctns->head);
}

static  pANTLR3_BASE_TREE
newDownNode             (pANTLR3_COMMON_TREE_NODE_STREAM ctns)
{
    pANTLR3_COMMON_TREE     dNode;
    pANTLR3_COMMON_TOKEN    token;

    token                                       = antlr3CommonTokenNew(ANTLR3_TOKEN_DOWN);
        token->textState                = ANTLR3_TEXT_CHARP;
        token->tokText.chars    = (pANTLR3_UCHAR)"DOWN";
    dNode                                       = antlr3CommonTreeNewFromToken(token);

    return  &(dNode->baseTree);
}

static  pANTLR3_BASE_TREE
newUpNode               (pANTLR3_COMMON_TREE_NODE_STREAM ctns)
{
    pANTLR3_COMMON_TREE     uNode;
    pANTLR3_COMMON_TOKEN    token;

    token                                       = antlr3CommonTokenNew(ANTLR3_TOKEN_UP);
        token->textState                = ANTLR3_TEXT_CHARP;
        token->tokText.chars    = (pANTLR3_UCHAR)"UP";
    uNode                                       = antlr3CommonTreeNewFromToken(token);

    return  &(uNode->baseTree);
}

/// Replace from start to stop child index of parent with t, which might
/// be a list.  Number of children may be different
/// after this call.  The stream is notified because it is walking the
/// tree and might need to know you are monkey-ing with the underlying
/// tree.  Also, it might be able to modify the node stream to avoid
/// re-streaming for future phases.
///
/// If parent is null, don't do anything; must be at root of overall tree.
/// Can't replace whatever points to the parent externally.  Do nothing.
///
static  void
replaceChildren                         (pANTLR3_TREE_NODE_STREAM tns, pANTLR3_BASE_TREE parent, ANTLR3_INT32 startChildIndex, ANTLR3_INT32 stopChildIndex, pANTLR3_BASE_TREE t)
{
        if      (parent != NULL)
        {
                pANTLR3_BASE_TREE_ADAPTOR       adaptor;
                pANTLR3_COMMON_TREE_ADAPTOR     cta;

                adaptor = tns->getTreeAdaptor(tns);
                cta             = (pANTLR3_COMMON_TREE_ADAPTOR)(adaptor->super);

                adaptor->replaceChildren(adaptor, parent, startChildIndex, stopChildIndex, t);
        }
}

static  pANTLR3_BASE_TREE
get                                                     (pANTLR3_TREE_NODE_STREAM tns, ANTLR3_INT32 k)
{
        if      (tns->ctns->p == -1)
        {
                fillBufferRoot(tns->ctns);
        }

        return (pANTLR3_BASE_TREE)tns->ctns->nodes->get(tns->ctns->nodes, k);
}

static  void
push                                            (pANTLR3_COMMON_TREE_NODE_STREAM ctns, ANTLR3_INT32 index)
{
        ctns->nodeStack->push(ctns->nodeStack, ANTLR3_FUNC_PTR(ctns->p), NULL); // Save current index
        ctns->tnstream->istream->seek(ctns->tnstream->istream, index);
}

static  ANTLR3_INT32
pop                                                     (pANTLR3_COMMON_TREE_NODE_STREAM ctns)
{
        ANTLR3_INT32    retVal;

        retVal = ANTLR3_UINT32_CAST(ctns->nodeStack->pop(ctns->nodeStack));
        ctns->tnstream->istream->seek(ctns->tnstream->istream, retVal);
        return retVal;
}
