| /// \file |
| /// Implementation of token/tree streams that are used by the |
| /// tree re-write rules to manipulate the tokens and trees produced |
| /// by rules that are subject to rewrite directives. |
| /// |
| |
| // [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 <antlr3rewritestreams.h> |
| |
| // Static support function forward declarations for the stream types. |
| // |
| static void reset (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream); |
| static void add (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream, void * el, void (ANTLR3_CDECL *freePtr)(void *)); |
| static void * next (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream); |
| static pANTLR3_BASE_TREE nextTree (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream); |
| static void * nextToken (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream); |
| static void * _next (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream); |
| static void * dupTok (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream, void * el); |
| static void * dupTree (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream, void * el); |
| static void * dupTreeNode (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream, void * el); |
| static pANTLR3_BASE_TREE toTree (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream, void * element); |
| static pANTLR3_BASE_TREE toTreeNode (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream, void * element); |
| static ANTLR3_BOOLEAN hasNext (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream); |
| static pANTLR3_BASE_TREE nextNode (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream); |
| static pANTLR3_BASE_TREE nextNodeNode (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream); |
| static pANTLR3_BASE_TREE nextNodeToken (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream); |
| static ANTLR3_UINT32 size (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream); |
| static void * getDescription (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream); |
| static void freeRS (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream); |
| static void expungeRS (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream); |
| |
| |
| // Place a now unused rewrite stream back on the rewrite stream pool |
| // so we can reuse it if we need to. |
| // |
| static void |
| freeRS (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream) |
| { |
| // Before placing the stream back in the pool, we |
| // need to clear any vector it has. This is so any |
| // free pointers that are associated with the |
| // entires are called. |
| // |
| if (stream->elements != NULL) |
| { |
| // Factory generated vectors can be returned to the |
| // vector factory for later reuse. |
| // |
| if (stream->elements->factoryMade == ANTLR3_TRUE) |
| { |
| pANTLR3_VECTOR_FACTORY factory = ((pANTLR3_COMMON_TREE_ADAPTOR)(stream->adaptor->super))->arboretum->vFactory; |
| factory->returnVector(factory, stream->elements); |
| |
| stream->elements = NULL; |
| } |
| else |
| { |
| // Other vectors we clear and allow to be reused if they come off the |
| // rewrite stream free stack and are reused. |
| // |
| stream->elements->clear(stream->elements); |
| stream->freeElements = ANTLR3_TRUE; |
| } |
| } |
| else |
| { |
| stream->freeElements = ANTLR3_FALSE; // Just in case |
| } |
| |
| // Add the stream into the recognizer stream stack vector |
| // adding the stream memory free routine so that |
| // it is thrown away when the stack vector is destroyed |
| // |
| stream->rec->state->rStreams->add(stream->rec->state->rStreams, stream, (void(*)(void *))expungeRS); |
| } |
| |
| /** Do special nilNode reuse detection for node streams. |
| */ |
| static void |
| freeNodeRS(pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream) |
| { |
| pANTLR3_BASE_TREE tree; |
| |
| // Before placing the stream back in the pool, we |
| // need to clear any vector it has. This is so any |
| // free pointers that are associated with the |
| // entires are called. However, if this particular function is called |
| // then we know that the entries in the stream are definately |
| // tree nodes. Hence we check to see if any of them were nilNodes as |
| // if they were, we can reuse them. |
| // |
| if (stream->elements != NULL) |
| { |
| // We have some elements to traverse |
| // |
| ANTLR3_UINT32 i; |
| |
| for (i = 1; i<= stream->elements->count; i++) |
| { |
| tree = (pANTLR3_BASE_TREE)(stream->elements->elements[i-1].element); |
| if (tree != NULL && tree->isNilNode(tree)) |
| { |
| // Had to remove this for now, check is not comprehensive enough |
| // tree->reuse(tree); |
| } |
| |
| } |
| // Factory generated vectors can be returned to the |
| // vector factory for later reuse. |
| // |
| if (stream->elements->factoryMade == ANTLR3_TRUE) |
| { |
| pANTLR3_VECTOR_FACTORY factory = ((pANTLR3_COMMON_TREE_ADAPTOR)(stream->adaptor->super))->arboretum->vFactory; |
| factory->returnVector(factory, stream->elements); |
| |
| stream->elements = NULL; |
| } |
| else |
| { |
| stream->elements->clear(stream->elements); |
| stream->freeElements = ANTLR3_TRUE; |
| } |
| } |
| else |
| { |
| if (stream->singleElement != NULL) |
| { |
| tree = (pANTLR3_BASE_TREE)(stream->singleElement); |
| if (tree->isNilNode(tree)) |
| { |
| // Had to remove this for now, check is not comprehensive enough |
| // tree->reuse(tree); |
| } |
| } |
| stream->singleElement = NULL; |
| stream->freeElements = ANTLR3_FALSE; // Just in case |
| } |
| |
| // Add the stream into the recognizer stream stack vector |
| // adding the stream memory free routine so that |
| // it is thrown away when the stack vector is destroyed |
| // |
| stream->rec->state->rStreams->add(stream->rec->state->rStreams, stream, (void(*)(void *))expungeRS); |
| } |
| static void |
| expungeRS(pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream) |
| { |
| |
| if (stream->freeElements == ANTLR3_TRUE && stream->elements != NULL) |
| { |
| stream->elements->free(stream->elements); |
| } |
| ANTLR3_FREE(stream); |
| } |
| |
| // Functions for creating streams |
| // |
| static pANTLR3_REWRITE_RULE_ELEMENT_STREAM |
| antlr3RewriteRuleElementStreamNewAE(pANTLR3_BASE_TREE_ADAPTOR adaptor, pANTLR3_BASE_RECOGNIZER rec, pANTLR3_UINT8 description) |
| { |
| pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream; |
| |
| // First - do we already have a rewrite stream that was returned |
| // to the pool? If we do, then we will just reuse it by resetting |
| // the generic interface. |
| // |
| if (rec->state->rStreams->count > 0) |
| { |
| // Remove the entry from the vector. We do not |
| // cause it to be freed by using remove. |
| // |
| stream = rec->state->rStreams->remove(rec->state->rStreams, rec->state->rStreams->count - 1); |
| |
| // We found a stream we can reuse. |
| // If the stream had a vector, then it will have been cleared |
| // when the freeRS was called that put it in this stack |
| // |
| } |
| else |
| { |
| // Ok, we need to allocate a new one as there were none on the stack. |
| // First job is to create the memory we need. |
| // |
| stream = (pANTLR3_REWRITE_RULE_ELEMENT_STREAM) ANTLR3_MALLOC((size_t)(sizeof(ANTLR3_REWRITE_RULE_ELEMENT_STREAM))); |
| |
| if (stream == NULL) |
| { |
| return NULL; |
| } |
| stream->elements = NULL; |
| stream->freeElements = ANTLR3_FALSE; |
| } |
| |
| // Populate the generic interface |
| // |
| stream->rec = rec; |
| stream->reset = reset; |
| stream->add = add; |
| stream->next = next; |
| stream->nextTree = nextTree; |
| stream->nextNode = nextNode; |
| stream->nextToken = nextToken; |
| stream->_next = _next; |
| stream->hasNext = hasNext; |
| stream->size = size; |
| stream->getDescription = getDescription; |
| stream->toTree = toTree; |
| stream->free = freeRS; |
| stream->singleElement = NULL; |
| |
| // Reset the stream to empty. |
| // |
| |
| stream->cursor = 0; |
| stream->dirty = ANTLR3_FALSE; |
| |
| // Install the description |
| // |
| stream->elementDescription = description; |
| |
| // Install the adaptor |
| // |
| stream->adaptor = adaptor; |
| |
| return stream; |
| } |
| |
| static pANTLR3_REWRITE_RULE_ELEMENT_STREAM |
| antlr3RewriteRuleElementStreamNewAEE(pANTLR3_BASE_TREE_ADAPTOR adaptor, pANTLR3_BASE_RECOGNIZER rec, pANTLR3_UINT8 description, void * oneElement) |
| { |
| pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream; |
| |
| // First job is to create the memory we need. |
| // |
| stream = antlr3RewriteRuleElementStreamNewAE(adaptor, rec, description); |
| |
| if (stream == NULL) |
| { |
| return NULL; |
| } |
| |
| // Stream seems good so we need to add the supplied element |
| // |
| if (oneElement != NULL) |
| { |
| stream->add(stream, oneElement, NULL); |
| } |
| return stream; |
| } |
| |
| static pANTLR3_REWRITE_RULE_ELEMENT_STREAM |
| antlr3RewriteRuleElementStreamNewAEV(pANTLR3_BASE_TREE_ADAPTOR adaptor, pANTLR3_BASE_RECOGNIZER rec, pANTLR3_UINT8 description, pANTLR3_VECTOR vector) |
| { |
| pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream; |
| |
| // First job is to create the memory we need. |
| // |
| stream = antlr3RewriteRuleElementStreamNewAE(adaptor, rec, description); |
| |
| if (stream == NULL) |
| { |
| return stream; |
| } |
| |
| // Stream seems good so we need to install the vector we were |
| // given. We assume that someone else is going to free the |
| // vector. |
| // |
| if (stream->elements != NULL && stream->elements->factoryMade == ANTLR3_FALSE && stream->freeElements == ANTLR3_TRUE ) |
| { |
| stream->elements->free(stream->elements); |
| } |
| stream->elements = vector; |
| stream->freeElements = ANTLR3_FALSE; |
| return stream; |
| } |
| |
| // Token rewrite stream ... |
| // |
| ANTLR3_API pANTLR3_REWRITE_RULE_TOKEN_STREAM |
| antlr3RewriteRuleTOKENStreamNewAE(pANTLR3_BASE_TREE_ADAPTOR adaptor, pANTLR3_BASE_RECOGNIZER rec, pANTLR3_UINT8 description) |
| { |
| pANTLR3_REWRITE_RULE_TOKEN_STREAM stream; |
| |
| // First job is to create the memory we need. |
| // |
| stream = antlr3RewriteRuleElementStreamNewAE(adaptor, rec, description); |
| |
| if (stream == NULL) |
| { |
| return stream; |
| } |
| |
| // Install the token based overrides |
| // |
| stream->dup = dupTok; |
| stream->nextNode = nextNodeToken; |
| |
| // No nextNode implementation for a token rewrite stream |
| // |
| return stream; |
| } |
| |
| ANTLR3_API pANTLR3_REWRITE_RULE_TOKEN_STREAM |
| antlr3RewriteRuleTOKENStreamNewAEE(pANTLR3_BASE_TREE_ADAPTOR adaptor, pANTLR3_BASE_RECOGNIZER rec, pANTLR3_UINT8 description, void * oneElement) |
| { |
| pANTLR3_REWRITE_RULE_TOKEN_STREAM stream; |
| |
| // First job is to create the memory we need. |
| // |
| stream = antlr3RewriteRuleElementStreamNewAEE(adaptor, rec, description, oneElement); |
| |
| // Install the token based overrides |
| // |
| stream->dup = dupTok; |
| stream->nextNode = nextNodeToken; |
| |
| // No nextNode implementation for a token rewrite stream |
| // |
| return stream; |
| } |
| |
| ANTLR3_API pANTLR3_REWRITE_RULE_TOKEN_STREAM |
| antlr3RewriteRuleTOKENStreamNewAEV(pANTLR3_BASE_TREE_ADAPTOR adaptor, pANTLR3_BASE_RECOGNIZER rec, pANTLR3_UINT8 description, pANTLR3_VECTOR vector) |
| { |
| pANTLR3_REWRITE_RULE_TOKEN_STREAM stream; |
| |
| // First job is to create the memory we need. |
| // |
| stream = antlr3RewriteRuleElementStreamNewAEV(adaptor, rec, description, vector); |
| |
| // Install the token based overrides |
| // |
| stream->dup = dupTok; |
| stream->nextNode = nextNodeToken; |
| |
| // No nextNode implementation for a token rewrite stream |
| // |
| return stream; |
| } |
| |
| // Subtree rewrite stream |
| // |
| ANTLR3_API pANTLR3_REWRITE_RULE_SUBTREE_STREAM |
| antlr3RewriteRuleSubtreeStreamNewAE(pANTLR3_BASE_TREE_ADAPTOR adaptor, pANTLR3_BASE_RECOGNIZER rec, pANTLR3_UINT8 description) |
| { |
| pANTLR3_REWRITE_RULE_SUBTREE_STREAM stream; |
| |
| // First job is to create the memory we need. |
| // |
| stream = antlr3RewriteRuleElementStreamNewAE(adaptor, rec, description); |
| |
| if (stream == NULL) |
| { |
| return stream; |
| } |
| |
| // Install the subtree based overrides |
| // |
| stream->dup = dupTree; |
| stream->nextNode = nextNode; |
| stream->free = freeNodeRS; |
| return stream; |
| |
| } |
| ANTLR3_API pANTLR3_REWRITE_RULE_SUBTREE_STREAM |
| antlr3RewriteRuleSubtreeStreamNewAEE(pANTLR3_BASE_TREE_ADAPTOR adaptor, pANTLR3_BASE_RECOGNIZER rec, pANTLR3_UINT8 description, void * oneElement) |
| { |
| pANTLR3_REWRITE_RULE_SUBTREE_STREAM stream; |
| |
| // First job is to create the memory we need. |
| // |
| stream = antlr3RewriteRuleElementStreamNewAEE(adaptor, rec, description, oneElement); |
| |
| if (stream == NULL) |
| { |
| return stream; |
| } |
| |
| // Install the subtree based overrides |
| // |
| stream->dup = dupTree; |
| stream->nextNode = nextNode; |
| stream->free = freeNodeRS; |
| |
| return stream; |
| } |
| |
| ANTLR3_API pANTLR3_REWRITE_RULE_SUBTREE_STREAM |
| antlr3RewriteRuleSubtreeStreamNewAEV(pANTLR3_BASE_TREE_ADAPTOR adaptor, pANTLR3_BASE_RECOGNIZER rec, pANTLR3_UINT8 description, pANTLR3_VECTOR vector) |
| { |
| pANTLR3_REWRITE_RULE_SUBTREE_STREAM stream; |
| |
| // First job is to create the memory we need. |
| // |
| stream = antlr3RewriteRuleElementStreamNewAEV(adaptor, rec, description, vector); |
| |
| if (stream == NULL) |
| { |
| return NULL; |
| } |
| |
| // Install the subtree based overrides |
| // |
| stream->dup = dupTree; |
| stream->nextNode = nextNode; |
| stream->free = freeNodeRS; |
| |
| return stream; |
| } |
| // Node rewrite stream ... |
| // |
| ANTLR3_API pANTLR3_REWRITE_RULE_NODE_STREAM |
| antlr3RewriteRuleNODEStreamNewAE(pANTLR3_BASE_TREE_ADAPTOR adaptor, pANTLR3_BASE_RECOGNIZER rec, pANTLR3_UINT8 description) |
| { |
| pANTLR3_REWRITE_RULE_NODE_STREAM stream; |
| |
| // First job is to create the memory we need. |
| // |
| stream = antlr3RewriteRuleElementStreamNewAE(adaptor, rec, description); |
| |
| if (stream == NULL) |
| { |
| return stream; |
| } |
| |
| // Install the node based overrides |
| // |
| stream->dup = dupTreeNode; |
| stream->toTree = toTreeNode; |
| stream->nextNode = nextNodeNode; |
| stream->free = freeNodeRS; |
| |
| return stream; |
| } |
| |
| ANTLR3_API pANTLR3_REWRITE_RULE_NODE_STREAM |
| antlr3RewriteRuleNODEStreamNewAEE(pANTLR3_BASE_TREE_ADAPTOR adaptor, pANTLR3_BASE_RECOGNIZER rec, pANTLR3_UINT8 description, void * oneElement) |
| { |
| pANTLR3_REWRITE_RULE_NODE_STREAM stream; |
| |
| // First job is to create the memory we need. |
| // |
| stream = antlr3RewriteRuleElementStreamNewAEE(adaptor, rec, description, oneElement); |
| |
| // Install the node based overrides |
| // |
| stream->dup = dupTreeNode; |
| stream->toTree = toTreeNode; |
| stream->nextNode = nextNodeNode; |
| stream->free = freeNodeRS; |
| |
| return stream; |
| } |
| |
| ANTLR3_API pANTLR3_REWRITE_RULE_NODE_STREAM |
| antlr3RewriteRuleNODEStreamNewAEV(pANTLR3_BASE_TREE_ADAPTOR adaptor, pANTLR3_BASE_RECOGNIZER rec, pANTLR3_UINT8 description, pANTLR3_VECTOR vector) |
| { |
| pANTLR3_REWRITE_RULE_NODE_STREAM stream; |
| |
| // First job is to create the memory we need. |
| // |
| stream = antlr3RewriteRuleElementStreamNewAEV(adaptor, rec, description, vector); |
| |
| // Install the Node based overrides |
| // |
| stream->dup = dupTreeNode; |
| stream->toTree = toTreeNode; |
| stream->nextNode = nextNodeNode; |
| stream->free = freeNodeRS; |
| |
| return stream; |
| } |
| |
| //---------------------------------------------------------------------- |
| // Static support functions |
| |
| /// Reset the condition of this stream so that it appears we have |
| /// not consumed any of its elements. Elements themselves are untouched. |
| /// |
| static void |
| reset (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream) |
| { |
| stream->dirty = ANTLR3_TRUE; |
| stream->cursor = 0; |
| } |
| |
| // Add a new pANTLR3_BASE_TREE to this stream |
| // |
| static void |
| add (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream, void * el, void (ANTLR3_CDECL *freePtr)(void *)) |
| { |
| if (el== NULL) |
| { |
| return; |
| } |
| // As we may be reusing a stream, we may already have allocated |
| // a rewrite stream vector. If we have then is will be empty if |
| // we have either zero or just one element in the rewrite stream |
| // |
| if (stream->elements != NULL && stream->elements->count > 0) |
| { |
| // We already have >1 entries in the stream. So we can just add this new element to the existing |
| // collection. |
| // |
| stream->elements->add(stream->elements, el, freePtr); |
| return; |
| } |
| if (stream->singleElement == NULL) |
| { |
| stream->singleElement = el; |
| return; |
| } |
| |
| // If we got here then we had only the one element so far |
| // and we must now create a vector to hold a collection of them |
| // |
| if (stream->elements == NULL) |
| { |
| pANTLR3_VECTOR_FACTORY factory = ((pANTLR3_COMMON_TREE_ADAPTOR)(stream->adaptor->super))->arboretum->vFactory; |
| |
| |
| stream->elements = factory->newVector(factory); |
| stream->freeElements = ANTLR3_TRUE; // We 'ummed it, so we play it son. |
| } |
| |
| stream->elements->add (stream->elements, stream->singleElement, freePtr); |
| stream->elements->add (stream->elements, el, freePtr); |
| stream->singleElement = NULL; |
| |
| return; |
| } |
| |
| /// Return the next element in the stream. If out of elements, throw |
| /// an exception unless size()==1. If size is 1, then return elements[0]. |
| /// Return a duplicate node/subtree if stream is out of elements and |
| /// size==1. If we've already used the element, dup (dirty bit set). |
| /// |
| static pANTLR3_BASE_TREE |
| nextTree(pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream) |
| { |
| ANTLR3_UINT32 n; |
| void * el; |
| |
| n = stream->size(stream); |
| |
| if ( stream->dirty || (stream->cursor >=n && n==1) ) |
| { |
| // if out of elements and size is 1, dup |
| // |
| el = stream->_next(stream); |
| return stream->dup(stream, el); |
| } |
| |
| // test size above then fetch |
| // |
| el = stream->_next(stream); |
| return el; |
| } |
| |
| /// Return the next element for a caller that wants just the token |
| /// |
| static void * |
| nextToken (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream) |
| { |
| return stream->_next(stream); |
| } |
| |
| /// Return the next element in the stream. If out of elements, throw |
| /// an exception unless size()==1. If size is 1, then return elements[0]. |
| /// |
| static void * |
| next (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream) |
| { |
| ANTLR3_UINT32 s; |
| |
| s = stream->size(stream); |
| if (stream->cursor >= s && s == 1) |
| { |
| pANTLR3_BASE_TREE el; |
| |
| el = stream->_next(stream); |
| |
| return stream->dup(stream, el); |
| } |
| |
| return stream->_next(stream); |
| } |
| |
| /// Do the work of getting the next element, making sure that it's |
| /// a tree node or subtree. Deal with the optimization of single- |
| /// element list versus list of size > 1. Throw an exception (or something similar) |
| /// if the stream is empty or we're out of elements and size>1. |
| /// You can override in a 'subclass' if necessary. |
| /// |
| static void * |
| _next (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream) |
| { |
| ANTLR3_UINT32 n; |
| pANTLR3_BASE_TREE t; |
| |
| n = stream->size(stream); |
| |
| if (n == 0) |
| { |
| // This means that the stream is empty |
| // |
| return NULL; // Caller must cope with this |
| } |
| |
| // Traversed all the available elements already? |
| // |
| if (stream->cursor >= n) |
| { |
| if (n == 1) |
| { |
| // Special case when size is single element, it will just dup a lot |
| // |
| return stream->toTree(stream, stream->singleElement); |
| } |
| |
| // Out of elements and the size is not 1, so we cannot assume |
| // that we just duplicate the entry n times (such as ID ent+ -> ^(ID ent)+) |
| // This means we ran out of elements earlier than was expected. |
| // |
| return NULL; // Caller must cope with this |
| } |
| |
| // Elements available either for duping or just available |
| // |
| if (stream->singleElement != NULL) |
| { |
| stream->cursor++; // Cursor advances even for single element as this tells us to dup() |
| return stream->toTree(stream, stream->singleElement); |
| } |
| |
| // More than just a single element so we extract it from the |
| // vector. |
| // |
| t = stream->toTree(stream, stream->elements->get(stream->elements, stream->cursor)); |
| stream->cursor++; |
| return t; |
| } |
| |
| #ifdef ANTLR3_WINDOWS |
| #pragma warning(push) |
| #pragma warning(disable : 4100) |
| #endif |
| /// When constructing trees, sometimes we need to dup a token or AST |
| /// subtree. Dup'ing a token means just creating another AST node |
| /// around it. For trees, you must call the adaptor.dupTree(). |
| /// |
| static void * |
| dupTok (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream, void * el) |
| { |
| ANTLR3_FPRINTF(stderr, "dup() cannot be called on a token rewrite stream!!"); |
| return NULL; |
| } |
| #ifdef ANTLR3_WINDOWS |
| #pragma warning(pop) |
| #endif |
| |
| /// When constructing trees, sometimes we need to dup a token or AST |
| /// subtree. Dup'ing a token means just creating another AST node |
| /// around it. For trees, you must call the adaptor.dupTree(). |
| /// |
| static void * |
| dupTree (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream, void * element) |
| { |
| return stream->adaptor->dupNode(stream->adaptor, (pANTLR3_BASE_TREE)element); |
| } |
| |
| #ifdef ANTLR3_WINDOWS |
| #pragma warning(push) |
| #pragma warning(disable : 4100) |
| #endif |
| /// When constructing trees, sometimes we need to dup a token or AST |
| /// subtree. Dup'ing a token means just creating another AST node |
| /// around it. For trees, you must call the adaptor.dupTree(). |
| /// |
| static void * |
| dupTreeNode (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream, void * element) |
| { |
| ANTLR3_FPRINTF(stderr, "dup() cannot be called on a node rewrite stream!!!"); |
| return NULL; |
| } |
| |
| |
| /// We don;t explicitly convert to a tree unless the call goes to |
| /// nextTree, which means rewrites are heterogeneous |
| /// |
| static pANTLR3_BASE_TREE |
| toTree (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream, void * element) |
| { |
| return (pANTLR3_BASE_TREE)element; |
| } |
| #ifdef ANTLR3_WINDOWS |
| #pragma warning(pop) |
| #endif |
| |
| /// Ensure stream emits trees; tokens must be converted to AST nodes. |
| /// AST nodes can be passed through unmolested. |
| /// |
| #ifdef ANTLR3_WINDOWS |
| #pragma warning(push) |
| #pragma warning(disable : 4100) |
| #endif |
| |
| static pANTLR3_BASE_TREE |
| toTreeNode (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream, void * element) |
| { |
| return stream->adaptor->dupNode(stream->adaptor, (pANTLR3_BASE_TREE)element); |
| } |
| |
| #ifdef ANTLR3_WINDOWS |
| #pragma warning(pop) |
| #endif |
| |
| /// Returns ANTLR3_TRUE if there is a next element available |
| /// |
| static ANTLR3_BOOLEAN |
| hasNext (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream) |
| { |
| if ( (stream->singleElement != NULL && stream->cursor < 1) |
| || (stream->elements != NULL && stream->cursor < stream->elements->size(stream->elements))) |
| { |
| return ANTLR3_TRUE; |
| } |
| else |
| { |
| return ANTLR3_FALSE; |
| } |
| } |
| |
| /// Get the next token from the list and create a node for it |
| /// This is the implementation for token streams. |
| /// |
| static pANTLR3_BASE_TREE |
| nextNodeToken(pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream) |
| { |
| return stream->adaptor->create(stream->adaptor, stream->_next(stream)); |
| } |
| |
| static pANTLR3_BASE_TREE |
| nextNodeNode(pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream) |
| { |
| return stream->_next(stream); |
| } |
| |
| /// Treat next element as a single node even if it's a subtree. |
| /// This is used instead of next() when the result has to be a |
| /// tree root node. Also prevents us from duplicating recently-added |
| /// children; e.g., ^(type ID)+ adds ID to type and then 2nd iteration |
| /// must dup the type node, but ID has been added. |
| /// |
| /// Referencing to a rule result twice is ok; dup entire tree as |
| /// we can't be adding trees; e.g., expr expr. |
| /// |
| static pANTLR3_BASE_TREE |
| nextNode (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream) |
| { |
| |
| ANTLR3_UINT32 n; |
| pANTLR3_BASE_TREE el = stream->_next(stream); |
| |
| n = stream->size(stream); |
| if (stream->dirty == ANTLR3_TRUE || (stream->cursor > n && n == 1)) |
| { |
| // We are out of elements and the size is 1, which means we just |
| // dup the node that we have |
| // |
| return stream->adaptor->dupNode(stream->adaptor, el); |
| } |
| |
| // We were not out of nodes, so the one we received is the one to return |
| // |
| return el; |
| } |
| |
| /// Number of elements available in the stream |
| /// |
| static ANTLR3_UINT32 |
| size (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream) |
| { |
| ANTLR3_UINT32 n = 0; |
| |
| /// Should be a count of one if singleElement is set. I copied this |
| /// logic from the java implementation, which I suspect is just guarding |
| /// against someone setting singleElement and forgetting to NULL it out |
| /// |
| if (stream->singleElement != NULL) |
| { |
| n = 1; |
| } |
| else |
| { |
| if (stream->elements != NULL) |
| { |
| return (ANTLR3_UINT32)(stream->elements->count); |
| } |
| } |
| return n; |
| } |
| |
| /// Returns the description string if there is one available (check for NULL). |
| /// |
| static void * |
| getDescription (pANTLR3_REWRITE_RULE_ELEMENT_STREAM stream) |
| { |
| if (stream->elementDescription == NULL) |
| { |
| stream->elementDescription = "<unknown source>"; |
| } |
| |
| return stream->elementDescription; |
| } |