Home | History | Annotate | Download | only in SlimParsing
      1 /*
      2  * [The "BSD license"]
      3  * Copyright (c) 2011 Terence Parr
      4  * All rights reserved.
      5  *
      6  * Conversion to C#:
      7  * Copyright (c) 2011 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
     34 {
     35     using System.Collections.Generic;
     36     using System;
     37     using System.Text;
     38 
     39     /** <summary>
     40      *  A pretty quick CharStream that pulls all data from an array
     41      *  directly.  Every method call counts in the lexer.  Java's
     42      *  strings aren't very good so I'm avoiding.
     43      *  </summary>
     44      */
     45     [System.Serializable]
     46     public class FastTokenStream
     47         : ITokenStream<SlimToken>
     48     {
     49         [System.NonSerialized]
     50         ITokenSource<SlimToken> _tokenSource;
     51 
     52         /** <summary>
     53          *  Record every single token pulled from the source so we can reproduce
     54          *  chunks of it later.
     55          *  </summary>
     56          */
     57         protected List<SlimToken> tokens;
     58 
     59         /** <summary>Skip tokens on any channel but this one; this is how we skip whitespace...</summary> */
     60         protected int channel = TokenChannels.Default;
     61 
     62         /** <summary>Track the last mark() call result value for use in rewind().</summary> */
     63         protected int lastMarker;
     64 
     65         /** <summary>
     66          *  The index into the tokens list of the current token (next token
     67          *  to consume).  p==-1 indicates that the tokens list is empty
     68          *  </summary>
     69          */
     70         protected int p = -1;
     71 
     72         public FastTokenStream()
     73         {
     74             tokens = new List<SlimToken>( 500 );
     75         }
     76 
     77         public FastTokenStream( ITokenSource<SlimToken> tokenSource )
     78             : this()
     79         {
     80             this._tokenSource = tokenSource;
     81         }
     82 
     83         public FastTokenStream( ITokenSource<SlimToken> tokenSource, int channel )
     84             : this( tokenSource )
     85         {
     86             this.channel = channel;
     87         }
     88 
     89         public int Index
     90         {
     91             get
     92             {
     93                 return p;
     94             }
     95         }
     96 
     97         /** <summary>Reset this token stream by setting its token source.</summary> */
     98         public void SetTokenSource( ITokenSource<SlimToken> tokenSource )
     99         {
    100             this._tokenSource = tokenSource;
    101             tokens.Clear();
    102             p = -1;
    103             channel = TokenChannels.Default;
    104         }
    105 
    106         /** <summary>
    107          *  Load all tokens from the token source and put in tokens.
    108          *  This is done upon first LT request because you might want to
    109          *  set some token type / channel overrides before filling buffer.
    110          *  </summary>
    111          */
    112         public void FillBuffer()
    113         {
    114             // fast return if the buffer is already full
    115             if ( p != -1 )
    116                 return;
    117 
    118             int index = 0;
    119             SlimToken t = _tokenSource.NextToken();
    120             while ( t.Type != CharStreamConstants.EndOfFile )
    121             {
    122                 //t.TokenIndex = index;
    123                 tokens.Add( t );
    124                 index++;
    125 
    126                 t = _tokenSource.NextToken();
    127             }
    128             // leave p pointing at first token on channel
    129             p = 0;
    130             p = SkipOffTokenChannels( p );
    131         }
    132 
    133         /** <summary>
    134          *  Move the input pointer to the next incoming token.  The stream
    135          *  must become active with LT(1) available.  consume() simply
    136          *  moves the input pointer so that LT(1) points at the next
    137          *  input symbol. Consume at least one token.
    138          *  </summary>
    139          *
    140          *  <remarks>
    141          *  Walk past any token not on the channel the parser is listening to.
    142          *  </remarks>
    143          */
    144         public void Consume()
    145         {
    146             if ( p < tokens.Count )
    147             {
    148                 p++;
    149                 p = SkipOffTokenChannels( p ); // leave p on valid token
    150             }
    151         }
    152 
    153         /** <summary>Given a starting index, return the index of the first on-channel token.</summary> */
    154         protected int SkipOffTokenChannels( int i )
    155         {
    156             int n = tokens.Count;
    157             while ( i < n && tokens[i].Channel != channel )
    158             {
    159                 i++;
    160             }
    161             return i;
    162         }
    163 
    164         protected int SkipOffTokenChannelsReverse( int i )
    165         {
    166             while ( i >= 0 && tokens[i].Channel != channel )
    167             {
    168                 i--;
    169             }
    170             return i;
    171         }
    172 
    173         public IList<SlimToken> GetTokens()
    174         {
    175             if ( p == -1 )
    176             {
    177                 FillBuffer();
    178             }
    179             return tokens;
    180         }
    181 
    182         public IList<SlimToken> GetTokens( int start, int stop )
    183         {
    184             return GetTokens( start, stop, (BitSet)null );
    185         }
    186 
    187         /** <summary>
    188          *  Given a start and stop index, return a List of all tokens in
    189          *  the token type BitSet.  Return null if no tokens were found.  This
    190          *  method looks at both on and off channel tokens.
    191          *  </summary>
    192          */
    193         public IList<SlimToken> GetTokens( int start, int stop, BitSet types )
    194         {
    195             if ( p == -1 )
    196             {
    197                 FillBuffer();
    198             }
    199             if ( stop >= tokens.Count )
    200             {
    201                 stop = tokens.Count - 1;
    202             }
    203             if ( start < 0 )
    204             {
    205                 start = 0;
    206             }
    207             if ( start > stop )
    208             {
    209                 return null;
    210             }
    211 
    212             // list = tokens[start:stop]:{Token t, t.getType() in types}
    213             List<SlimToken> filteredTokens = new List<SlimToken>();
    214             for ( int i = start; i <= stop; i++ )
    215             {
    216                 SlimToken t = tokens[i];
    217                 if ( types == null || types.Member( t.Type ) )
    218                 {
    219                     filteredTokens.Add( t );
    220                 }
    221             }
    222             if ( filteredTokens.Count == 0 )
    223             {
    224                 filteredTokens = null;
    225             }
    226             return filteredTokens;
    227         }
    228 
    229         public IList<SlimToken> GetTokens( int start, int stop, IList<int> types )
    230         {
    231             return GetTokens( start, stop, new BitSet( types ) );
    232         }
    233 
    234         public IList<SlimToken> GetTokens( int start, int stop, int ttype )
    235         {
    236             return GetTokens( start, stop, BitSet.Of( ttype ) );
    237         }
    238 
    239         /** <summary>
    240          *  Get the ith token from the current position 1..n where k=1 is the
    241          *  first symbol of lookahead.
    242          *  </summary>
    243          */
    244         public SlimToken LT( int k )
    245         {
    246             if ( p == -1 )
    247             {
    248                 FillBuffer();
    249             }
    250             if ( k == 0 )
    251             {
    252                 return default( SlimToken );
    253             }
    254             if ( k < 0 )
    255             {
    256                 return LB( -k );
    257             }
    258             //System.out.print("LT(p="+p+","+k+")=");
    259             if ( ( p + k - 1 ) >= tokens.Count )
    260             {
    261                 return new SlimToken(TokenTypes.EndOfFile);
    262             }
    263             //System.out.println(tokens.get(p+k-1));
    264             int i = p;
    265             int n = 1;
    266             // find k good tokens
    267             while ( n < k )
    268             {
    269                 // skip off-channel tokens
    270                 i = SkipOffTokenChannels( i + 1 ); // leave p on valid token
    271                 n++;
    272             }
    273             if ( i >= tokens.Count )
    274             {
    275                 return new SlimToken(TokenTypes.EndOfFile);
    276             }
    277             return tokens[i];
    278         }
    279 
    280         /** <summary>Look backwards k tokens on-channel tokens</summary> */
    281         protected SlimToken LB( int k )
    282         {
    283             //System.out.print("LB(p="+p+","+k+") ");
    284             if ( p == -1 )
    285             {
    286                 FillBuffer();
    287             }
    288             if ( k == 0 )
    289             {
    290                 return default( SlimToken );
    291             }
    292             if ( ( p - k ) < 0 )
    293             {
    294                 return default( SlimToken );
    295             }
    296 
    297             int i = p;
    298             int n = 1;
    299             // find k good tokens looking backwards
    300             while ( n <= k )
    301             {
    302                 // skip off-channel tokens
    303                 i = SkipOffTokenChannelsReverse( i - 1 ); // leave p on valid token
    304                 n++;
    305             }
    306             if ( i < 0 )
    307             {
    308                 return default( SlimToken );
    309             }
    310             return tokens[i];
    311         }
    312 
    313         /** <summary>
    314          *  Return absolute token i; ignore which channel the tokens are on;
    315          *  that is, count all tokens not just on-channel tokens.
    316          *  </summary>
    317          */
    318         public SlimToken Get( int i )
    319         {
    320             return tokens[i];
    321         }
    322 
    323         public int LA( int i )
    324         {
    325             return LT( i ).Type;
    326         }
    327 
    328         public int Mark()
    329         {
    330             if ( p == -1 )
    331             {
    332                 FillBuffer();
    333             }
    334             lastMarker = Index;
    335             return lastMarker;
    336         }
    337 
    338         public void Release( int marker )
    339         {
    340             // no resources to release
    341         }
    342 
    343         public int Count
    344         {
    345             get
    346             {
    347                 return tokens.Count;
    348             }
    349         }
    350 
    351         public void Rewind( int marker )
    352         {
    353             Seek( marker );
    354         }
    355 
    356         public void Rewind()
    357         {
    358             Seek( lastMarker );
    359         }
    360 
    361         public void Reset()
    362         {
    363             p = 0;
    364             lastMarker = 0;
    365         }
    366 
    367         public void Seek( int index )
    368         {
    369             p = index;
    370         }
    371 
    372         public ITokenSource<SlimToken> TokenSource
    373         {
    374             get
    375             {
    376                 return _tokenSource;
    377             }
    378         }
    379 
    380         public string SourceName
    381         {
    382             get
    383             {
    384                 return TokenSource.SourceName;
    385             }
    386         }
    387 
    388         public override string ToString()
    389         {
    390             if ( p == -1 )
    391             {
    392                 throw new InvalidOperationException( "Buffer is not yet filled." );
    393             }
    394             return ToString( 0, tokens.Count - 1 );
    395         }
    396 
    397         public virtual string ToString( int start, int stop )
    398         {
    399             if ( start < 0 || stop < 0 )
    400             {
    401                 return null;
    402             }
    403             if ( p == -1 )
    404             {
    405                 throw new InvalidOperationException( "Buffer is not yet filled." );
    406             }
    407             if ( stop >= tokens.Count )
    408             {
    409                 stop = tokens.Count - 1;
    410             }
    411             StringBuilder buf = new StringBuilder();
    412             for ( int i = start; i <= stop; i++ )
    413             {
    414                 SlimToken t = tokens[i];
    415                 SlimLexer lexer = _tokenSource as SlimLexer;
    416                 if ( lexer != null )
    417                 {
    418                     SlimStringStream input = lexer.CharStream as SlimStringStream;
    419                     if ( input != null )
    420                     {
    421                         string text = input.Substring( t.StartIndex, t.StopIndex - t.StartIndex + 1 );
    422                         buf.Append( text );
    423                     }
    424                 }
    425             }
    426             return buf.ToString();
    427         }
    428 
    429         public virtual string ToString( IToken start, IToken stop )
    430         {
    431             if ( start != null && stop != null )
    432             {
    433                 return ToString( start.TokenIndex, stop.TokenIndex );
    434             }
    435             return null;
    436         }
    437     }
    438 }
    439