• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.</summary>
75          */
76         protected bool dirty = false;
77 
78         /** <summary>The element or stream description; usually has name of the token or
79          *  rule reference that this list tracks.  Can include rulename too, but
80          *  the exception would track that info.
81          */
82         protected string elementDescription;
83         protected ITreeAdaptor adaptor;
84 
RewriteRuleElementStream( ITreeAdaptor adaptor, string elementDescription )85         public RewriteRuleElementStream( ITreeAdaptor adaptor, string elementDescription )
86         {
87             this.elementDescription = elementDescription;
88             this.adaptor = adaptor;
89         }
90 
91         /** <summary>Create a stream with one element</summary> */
RewriteRuleElementStream( ITreeAdaptor adaptor, string elementDescription, object oneElement )92         public RewriteRuleElementStream( ITreeAdaptor adaptor, string elementDescription, object oneElement )
93             : this( adaptor, elementDescription )
94         {
95             Add( oneElement );
96         }
97 
98         /** <summary>Create a stream, but feed off an existing list</summary> */
RewriteRuleElementStream( ITreeAdaptor adaptor, string elementDescription, IList elements )99         public RewriteRuleElementStream( ITreeAdaptor adaptor, string elementDescription, IList elements )
100             : this( adaptor, elementDescription )
101         {
102             this.singleElement = null;
103             this.elements = elements;
104         }
105 
106         /** <summary>
107          *  Reset the condition of this stream so that it appears we have
108          *  not consumed any of its elements.  Elements themselves are untouched.
109          *  Once we reset the stream, any future use will need duplicates.  Set
110          *  the dirty bit.
111          *  </summary>
112          */
Reset()113         public virtual void Reset()
114         {
115             cursor = 0;
116             dirty = true;
117         }
118 
Add( object el )119         public virtual void Add( object el )
120         {
121             //System.out.println("add '"+elementDescription+"' is "+el);
122             if ( el == null )
123             {
124                 return;
125             }
126             if ( elements != null )
127             { // if in list, just add
128                 elements.Add( el );
129                 return;
130             }
131             if ( singleElement == null )
132             { // no elements yet, track w/o list
133                 singleElement = el;
134                 return;
135             }
136             // adding 2nd element, move to list
137             elements = new List<object>( 5 );
138             elements.Add( singleElement );
139             singleElement = null;
140             elements.Add( el );
141         }
142 
143         /** <summary>
144          *  Return the next element in the stream.  If out of elements, throw
145          *  an exception unless size()==1.  If size is 1, then return elements[0].
146          *  Return a duplicate node/subtree if stream is out of elements and
147          *  size==1.  If we've already used the element, dup (dirty bit set).
148          *  </summary>
149          */
NextTree()150         public virtual object NextTree()
151         {
152             int n = Count;
153             if ( dirty || ( cursor >= n && n == 1 ) )
154             {
155                 // if out of elements and size is 1, dup
156                 object el = NextCore();
157                 return Dup( el );
158             }
159             // test size above then fetch
160             object el2 = NextCore();
161             return el2;
162         }
163 
164         /** <summary>
165          *  Do the work of getting the next element, making sure that it's
166          *  a tree node or subtree.  Deal with the optimization of single-
167          *  element list versus list of size > 1.  Throw an exception
168          *  if the stream is empty or we're out of elements and size>1.
169          *  protected so you can override in a subclass if necessary.
170          *  </summary>
171          */
NextCore()172         protected virtual object NextCore()
173         {
174             int n = Count;
175             if ( n == 0 )
176             {
177                 throw new RewriteEmptyStreamException( elementDescription );
178             }
179             if ( cursor >= n )
180             { // out of elements?
181                 if ( n == 1 )
182                 {  // if size is 1, it's ok; return and we'll dup
183                     return ToTree( singleElement );
184                 }
185                 // out of elements and size was not 1, so we can't dup
186                 throw new RewriteCardinalityException( elementDescription );
187             }
188             // we have elements
189             if ( singleElement != null )
190             {
191                 cursor++; // move cursor even for single element list
192                 return ToTree( singleElement );
193             }
194             // must have more than one in list, pull from elements
195             object o = ToTree( elements[cursor] );
196             cursor++;
197             return o;
198         }
199 
200         /** <summary>
201          *  When constructing trees, sometimes we need to dup a token or AST
202          * 	subtree.  Dup'ing a token means just creating another AST node
203          *  around it.  For trees, you must call the adaptor.dupTree() unless
204          *  the element is for a tree root; then it must be a node dup.
205          *  </summary>
206          */
Dup( object el )207         protected abstract object Dup( object el );
208 
209         /** <summary>
210          *  Ensure stream emits trees; tokens must be converted to AST nodes.
211          *  AST nodes can be passed through unmolested.
212          *  </summary>
213          */
ToTree( object el )214         protected virtual object ToTree( object el )
215         {
216             return el;
217         }
218 
219         public virtual bool HasNext
220         {
221             get
222             {
223                 return ( singleElement != null && cursor < 1 ) ||
224                       ( elements != null && cursor < elements.Count );
225             }
226         }
227 
228         public virtual int Count
229         {
230             get
231             {
232                 int n = 0;
233                 if ( singleElement != null )
234                 {
235                     n = 1;
236                 }
237                 if ( elements != null )
238                 {
239                     return elements.Count;
240                 }
241                 return n;
242             }
243         }
244 
245         public virtual string Description
246         {
247             get
248             {
249                 return elementDescription;
250             }
251         }
252     }
253 }
254