Home | History | Annotate | Download | only in Tree
      1 /*
      2  * [The "BSD licence"]
      3  * Copyright (c) 2005-2008 Terence Parr
      4  * All rights reserved.
      5  *
      6  * Conversion to C#:
      7  * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc.
      8  * All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. The name of the author may not be used to endorse or promote products
     19  *    derived from this software without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 namespace Antlr.Runtime.Tree
     34 {
     35     using System.Collections.Generic;
     36     using IList = System.Collections.IList;
     37 
     38     /** <summary>
     39      *  A generic list of elements tracked in an alternative to be used in
     40      *  a -> rewrite rule.  We need to subclass to fill in the next() method,
     41      *  which returns either an AST node wrapped around a token payload or
     42      *  an existing subtree.
     43      *  </summary>
     44      *
     45      *  <remarks>
     46      *  Once you start next()ing, do not try to add more elements.  It will
     47      *  break the cursor tracking I believe.
     48      *
     49      *  TODO: add mechanism to detect/puke on modification after reading from stream
     50      *  </remarks>
     51      *
     52      *  <see cref="RewriteRuleSubtreeStream"/>
     53      *  <see cref="RewriteRuleTokenStream"/>
     54      */
     55     [System.Serializable]
     56     public abstract class RewriteRuleElementStream
     57     {
     58         /** <summary>
     59          *  Cursor 0..n-1.  If singleElement!=null, cursor is 0 until you next(),
     60          *  which bumps it to 1 meaning no more elements.
     61          *  </summary>
     62          */
     63         protected int cursor = 0;
     64 
     65         /** <summary>Track single elements w/o creating a list.  Upon 2nd add, alloc list */
     66         protected object singleElement;
     67 
     68         /** <summary>The list of tokens or subtrees we are tracking */
     69         protected IList elements;
     70 
     71         /** <summary>Once a node / subtree has been used in a stream, it must be dup'd
     72          *  from then on.  Streams are reset after subrules so that the streams
     73          *  can be reused in future subrules.  So, reset must set a dirty bit.
     74          *  If dirty, then next() always returns a dup.
     75          *
     76          *  I wanted to use "naughty bit" here, but couldn't think of a way
     77          *  to use "naughty".
     78          */
     79         protected bool dirty = false;
     80 
     81         /** <summary>The element or stream description; usually has name of the token or
     82          *  rule reference that this list tracks.  Can include rulename too, but
     83          *  the exception would track that info.
     84          */
     85         protected string elementDescription;
     86         protected ITreeAdaptor adaptor;
     87 
     88         public RewriteRuleElementStream( ITreeAdaptor adaptor, string elementDescription )
     89         {
     90             this.elementDescription = elementDescription;
     91             this.adaptor = adaptor;
     92         }
     93 
     94         /** <summary>Create a stream with one element</summary> */
     95         public RewriteRuleElementStream( ITreeAdaptor adaptor, string elementDescription, object oneElement )
     96             : this( adaptor, elementDescription )
     97         {
     98             Add( oneElement );
     99         }
    100 
    101         /** <summary>Create a stream, but feed off an existing list</summary> */
    102         public RewriteRuleElementStream( ITreeAdaptor adaptor, string elementDescription, IList elements )
    103             : this( adaptor, elementDescription )
    104         {
    105             this.singleElement = null;
    106             this.elements = elements;
    107         }
    108 
    109         /** <summary>
    110          *  Reset the condition of this stream so that it appears we have
    111          *  not consumed any of its elements.  Elements themselves are untouched.
    112          *  Once we reset the stream, any future use will need duplicates.  Set
    113          *  the dirty bit.
    114          *  </summary>
    115          */
    116         public virtual void Reset()
    117         {
    118             cursor = 0;
    119             dirty = true;
    120         }
    121 
    122         public virtual void Add( object el )
    123         {
    124             //System.out.println("add '"+elementDescription+"' is "+el);
    125             if ( el == null )
    126             {
    127                 return;
    128             }
    129             if ( elements != null )
    130             { // if in list, just add
    131                 elements.Add( el );
    132                 return;
    133             }
    134             if ( singleElement == null )
    135             { // no elements yet, track w/o list
    136                 singleElement = el;
    137                 return;
    138             }
    139             // adding 2nd element, move to list
    140             elements = new List<object>( 5 );
    141             elements.Add( singleElement );
    142             singleElement = null;
    143             elements.Add( el );
    144         }
    145 
    146         /** <summary>
    147          *  Return the next element in the stream.  If out of elements, throw
    148          *  an exception unless size()==1.  If size is 1, then return elements[0].
    149          *  Return a duplicate node/subtree if stream is out of elements and
    150          *  size==1.  If we've already used the element, dup (dirty bit set).
    151          *  </summary>
    152          */
    153         public virtual object NextTree()
    154         {
    155             int n = Count;
    156             if ( dirty || ( cursor >= n && n == 1 ) )
    157             {
    158                 // if out of elements and size is 1, dup
    159                 object el = NextCore();
    160                 return Dup( el );
    161             }
    162             // test size above then fetch
    163             object el2 = NextCore();
    164             return el2;
    165         }
    166 
    167         /** <summary>
    168          *  Do the work of getting the next element, making sure that it's
    169          *  a tree node or subtree.  Deal with the optimization of single-
    170          *  element list versus list of size > 1.  Throw an exception
    171          *  if the stream is empty or we're out of elements and size>1.
    172          *  protected so you can override in a subclass if necessary.
    173          *  </summary>
    174          */
    175         protected virtual object NextCore()
    176         {
    177             int n = Count;
    178             if ( n == 0 )
    179             {
    180                 throw new RewriteEmptyStreamException( elementDescription );
    181             }
    182             if ( cursor >= n )
    183             { // out of elements?
    184                 if ( n == 1 )
    185                 {  // if size is 1, it's ok; return and we'll dup
    186                     return ToTree( singleElement );
    187                 }
    188                 // out of elements and size was not 1, so we can't dup
    189                 throw new RewriteCardinalityException( elementDescription );
    190             }
    191             // we have elements
    192             if ( singleElement != null )
    193             {
    194                 cursor++; // move cursor even for single element list
    195                 return ToTree( singleElement );
    196             }
    197             // must have more than one in list, pull from elements
    198             object o = ToTree( elements[cursor] );
    199             cursor++;
    200             return o;
    201         }
    202 
    203         /** <summary>
    204          *  When constructing trees, sometimes we need to dup a token or AST
    205          * 	subtree.  Dup'ing a token means just creating another AST node
    206          *  around it.  For trees, you must call the adaptor.dupTree() unless
    207          *  the element is for a tree root; then it must be a node dup.
    208          *  </summary>
    209          */
    210         protected abstract object Dup( object el );
    211 
    212         /** <summary>
    213          *  Ensure stream emits trees; tokens must be converted to AST nodes.
    214          *  AST nodes can be passed through unmolested.
    215          *  </summary>
    216          */
    217         protected virtual object ToTree( object el )
    218         {
    219             return el;
    220         }
    221 
    222         public virtual bool HasNext
    223         {
    224             get
    225             {
    226                 return ( singleElement != null && cursor < 1 ) ||
    227                       ( elements != null && cursor < elements.Count );
    228             }
    229         }
    230 
    231         public virtual int Count
    232         {
    233             get
    234             {
    235                 int n = 0;
    236                 if ( singleElement != null )
    237                 {
    238                     n = 1;
    239                 }
    240                 if ( elements != null )
    241                 {
    242                     return elements.Count;
    243                 }
    244                 return n;
    245             }
    246         }
    247 
    248         public virtual string Description
    249         {
    250             get
    251             {
    252                 return elementDescription;
    253             }
    254         }
    255     }
    256 }
    257