View Javadoc

1   package org.codehaus.groovy.syntax.lexer;
2   
3   import org.codehaus.groovy.syntax.ReadException;
4   import org.codehaus.groovy.syntax.Token;
5   
6   /***
7    *  Lexes Groovy, counting braces.  Considers itself at end of stream
8    *  when the } count exceeds the { count.
9    *
10   *  @author Chris Poirier
11   */
12  
13  public class GroovyExpressionLexer extends GroovyLexerBase implements Delimiter
14  {
15  
16      protected boolean delimited = true;   // When true, the lexer can do its delimiting
17      protected boolean finished  = false;  // Set when we reach the delimiter
18      protected int     balance   = 0;      // The current number of unmatched open-braces
19  
20  
21     /***
22      *  Finds and returns (and consumes) the next token from the underlying stream.
23      *  Returns null when out of tokens.  We let the GroovyLexerBase version deal
24      *  with delegation stuff.
25      */
26  
27      public Token nextToken() throws ReadException, LexerException
28      {
29          if( finished )
30          {
31              return null;
32          }
33          else
34          {
35              return super.nextToken();
36          }
37  
38      }
39  
40  
41  
42    //---------------------------------------------------------------------------
43    // DELIMITER ROUTINES
44  
45  
46     /***
47      *  Turns delimiting on or off.  This should affect <code>la()</code>
48      *  and <code>consume()</code>.  However, once the delimiter has been
49      *  reached, this routine should have no effect.
50      */
51  
52      public void delimit( boolean delimited )
53      {
54          this.delimited = delimited;
55      }
56  
57  
58  
59     /***
60      *  Returns true if the lexer is applying its delimiter policy.
61      */
62  
63      public boolean isDelimited()
64      {
65          return this.delimited;
66      }
67  
68  
69  
70     /***
71      *  Returns true if the lexer stream is dry.
72      */
73  
74      public boolean isFinished()
75      {
76          return finished;
77      }
78  
79  
80  
81     /***
82      *  Restarts the lexer stream after a <code>finish()</code>
83      *  and some intevening act (like a new source).
84      */
85  
86      protected void restart()
87      {
88          finished = false;
89      }
90  
91  
92  
93     /***
94      *  Stops the lexer stream.
95      */
96  
97      protected void finish()
98      {
99          finished = true;
100     }
101 
102 
103 
104 
105   //---------------------------------------------------------------------------
106   // DELEGATION
107 
108 
109    /***
110     *  Delegates our duties to another Lexer.
111     */
112 
113     public void delegate( Lexer to )
114     {
115         this.delegate = to;
116         delimit( false );
117         to.setSource( this );
118     }
119 
120 
121 
122    /***
123     *  Retakes responsibility for our duties.
124     */
125 
126     public void undelegate()
127     {
128         if( delegate != null )
129         {
130             delegate.unsetSource( );
131             delegate = null;
132             delimit( true );
133         }
134     }
135 
136 
137 
138   //---------------------------------------------------------------------------
139   // STREAM ROUTINES
140 
141 
142 
143    /***
144     *  Returns the next <code>k</code>th character, without consuming any.
145     */
146 
147     public char la(int k) throws LexerException, ReadException
148     {
149         if( source != null )
150         {
151             if( delimited )
152             {
153                 char c = ' ';
154                 int balance = this.balance;
155                 for( int i = 1; i <= k && balance >= 0; i++ )
156                 {
157                     c = source.la(k);
158                     switch( c )
159                     {
160                         case '{':
161                             balance++;
162                             break;
163                         case '}':
164                             balance--;
165                             break;
166                     }
167                 }
168 
169                 if( balance >= 0 )
170                 {
171                     return c;
172                 }
173                 else
174                 {
175                     return CharStream.EOS;
176                 }
177 
178             }
179             else
180             {
181                 return source.la(k);
182             }
183 
184         }
185         else
186         {
187             return CharStream.EOS;
188         }
189     }
190 
191 
192 
193    /***
194     *  Eats a character from the input stream.
195     */
196 
197     public char consume() throws LexerException, ReadException
198     {
199         if( source != null )
200         {
201             if( delimited )
202             {
203                 char c = source.la(1);
204                 switch( c )
205                 {
206                     case '{':
207                         balance++;
208                         break;
209                     case '}':
210                         balance--;
211                         break;
212                 }
213 
214                 if( balance >= 0 )
215                 {
216                     return source.consume();
217                 }
218                 else
219                 {
220                     finish();
221                 }
222             }
223             else
224             {
225                 return source.consume();
226             }
227         }
228 
229         return CharStream.EOS;
230     }
231 
232 }