001 /* 002 $Id: Token.java,v 1.29 2005/04/12 15:04:59 jstrachan Exp $ 003 004 Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved. 005 006 Redistribution and use of this software and associated documentation 007 ("Software"), with or without modification, are permitted provided 008 that the following conditions are met: 009 010 1. Redistributions of source code must retain copyright 011 statements and notices. Redistributions must also contain a 012 copy of this document. 013 014 2. Redistributions in binary form must reproduce the 015 above copyright notice, this list of conditions and the 016 following disclaimer in the documentation and/or other 017 materials provided with the distribution. 018 019 3. The name "groovy" must not be used to endorse or promote 020 products derived from this Software without prior written 021 permission of The Codehaus. For written permission, 022 please contact info@codehaus.org. 023 024 4. Products derived from this Software may not be called "groovy" 025 nor may "groovy" appear in their names without prior written 026 permission of The Codehaus. "groovy" is a registered 027 trademark of The Codehaus. 028 029 5. Due credit should be given to The Codehaus - 030 http://groovy.codehaus.org/ 031 032 THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS 033 ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT 034 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 035 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 036 THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 037 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 038 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 039 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 040 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 041 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 042 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 043 OF THE POSSIBILITY OF SUCH DAMAGE. 044 045 */ 046 047 package org.codehaus.groovy.syntax; 048 049 import org.codehaus.groovy.GroovyBugError; 050 051 052 /** 053 * A <code>CSTNode</code> produced by the <code>Lexer</code>. 054 * 055 * @see Lexer 056 * @see Parser 057 * @see Token 058 * @see Reduction 059 * @see Types 060 * 061 * @author <a href="mailto:bob@werken.com">bob mcwhirter</a> 062 * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a> 063 * 064 * @version $Id: Token.java,v 1.29 2005/04/12 15:04:59 jstrachan Exp $ 065 */ 066 067 public class Token extends CSTNode 068 { 069 public static final Token NULL = new Token(); 070 public static final Token EOF = new Token( Types.EOF, "", -1, -1 ); 071 072 073 //--------------------------------------------------------------------------- 074 // TOKEN INITIALIZATION AND SUCH 075 076 private int type = Types.UNKNOWN; // the actual type identified by the lexer 077 private int meaning = Types.UNKNOWN; // an interpretation applied to the token after the fact 078 079 private String text = ""; // the text of the token 080 private int startLine = -1; // the source line on which the token begins 081 private int startColumn = -1; // the source column on which the token begins 082 083 084 /** 085 * Initializes the Token with the specified information. 086 */ 087 088 public Token( int type, String text, int startLine, int startColumn ) 089 { 090 this.type = type; 091 this.meaning = type; 092 this.text = text; 093 this.startLine = startLine; 094 this.startColumn = startColumn; 095 } 096 097 098 /** 099 * Initializes the NULL Token. 100 */ 101 102 private Token() { } 103 104 105 106 /** 107 * Returns a copy of this Token. 108 */ 109 110 public Token dup() 111 { 112 Token token = new Token( this.type, this.text, this.startLine, this.startColumn ); 113 token.setMeaning( this.meaning ); 114 115 return token; 116 } 117 118 119 120 121 //--------------------------------------------------------------------------- 122 // NODE IDENTIFICATION AND MEANING 123 124 125 /** 126 * Returns the meaning of this node. If the node isEmpty(), returns 127 * the type of Token.NULL. 128 */ 129 130 public int getMeaning() 131 { 132 return meaning; 133 } 134 135 136 137 /** 138 * Sets the meaning for this node (and it's root Token). Not 139 * valid if the node isEmpty(). Returns this token, for 140 * convenience. 141 */ 142 143 public CSTNode setMeaning( int meaning ) 144 { 145 this.meaning = meaning; 146 return this; 147 } 148 149 150 151 /** 152 * Returns the actual type of the node. If the node isEmpty(), returns 153 * the type of Token.NULL. 154 */ 155 156 public int getType() 157 { 158 return type; 159 } 160 161 162 163 164 //--------------------------------------------------------------------------- 165 // MEMBER ACCESS 166 167 168 /** 169 * Returns the number of elements in the node (including root). 170 */ 171 172 public int size() 173 { 174 return 1; 175 } 176 177 178 179 /** 180 * Returns the specified element, or null. 181 */ 182 183 public CSTNode get( int index ) 184 { 185 if( index > 0 ) 186 { 187 throw new GroovyBugError( "attempt to access Token element other than root" ); 188 } 189 190 return this; 191 } 192 193 194 195 /** 196 * Returns the root of the node. By convention, all nodes have 197 * a Token as the first element (or root), which indicates the type 198 * of the node. May return null if the node <code>isEmpty()</code>. 199 */ 200 201 public Token getRoot() 202 { 203 return this; 204 } 205 206 207 208 /** 209 * Returns the text of the root node. Uses <code>getRoot(true)</code> 210 * to get the root, so you will only receive null in return if the 211 * root token returns it. 212 */ 213 214 public String getRootText() 215 { 216 return text; 217 } 218 219 220 221 /** 222 * Returns the text of the token. Equivalent to 223 * <code>getRootText()</code> when called directly. 224 */ 225 226 public String getText() 227 { 228 return text; 229 } 230 231 232 233 /** 234 * Not advisable, but if you need to adjust the token's text, this 235 * will do it. 236 */ 237 238 public void setText( String text ) 239 { 240 this.text = text; 241 } 242 243 244 245 /** 246 * Returns the starting line of the node. Returns -1 247 * if not known. 248 */ 249 250 public int getStartLine() 251 { 252 return startLine; 253 } 254 255 256 257 /** 258 * Returns the starting column of the node. Returns -1 259 * if not known. 260 */ 261 262 public int getStartColumn() 263 { 264 return startColumn; 265 } 266 267 268 269 270 //--------------------------------------------------------------------------- 271 // OPERATIONS 272 273 274 /** 275 * Creates a <code>Reduction</code> from this token. Returns self if the 276 * node is already a <code>Reduction</code>. 277 */ 278 279 public Reduction asReduction() 280 { 281 return new Reduction( this ); 282 } 283 284 285 286 /** 287 * Creates a <code>Reduction</code> from this token, adding the supplied 288 * node as the second element. 289 */ 290 291 public Reduction asReduction( CSTNode second ) 292 { 293 Reduction created = asReduction(); 294 created.add( second ); 295 return created; 296 } 297 298 299 300 /** 301 * Creates a <code>Reduction</code> from this token, adding the supplied 302 * nodes as the second and third element, respectively. 303 */ 304 305 public Reduction asReduction( CSTNode second, CSTNode third ) 306 { 307 Reduction created = asReduction( second ); 308 created.add( third ); 309 return created; 310 } 311 312 313 314 /** 315 * Creates a <code>Reduction</code> from this token, adding the supplied 316 * nodes as the second, third, and fourth element, respectively. 317 */ 318 319 public Reduction asReduction( CSTNode second, CSTNode third, CSTNode fourth ) 320 { 321 Reduction created = asReduction( second, third ); 322 created.add( fourth ); 323 return created; 324 } 325 326 327 328 329 //--------------------------------------------------------------------------- 330 // TOKEN FACTORIES 331 332 333 /** 334 * Creates a token that represents a keyword. Returns null if the 335 * specified text isn't a keyword. 336 */ 337 338 public static Token newKeyword( String text, int startLine, int startColumn ) 339 { 340 341 int type = Types.lookupKeyword( text ); 342 if( type != Types.UNKNOWN ) 343 { 344 return new Token( type, text, startLine, startColumn ); 345 } 346 347 return null; 348 349 } 350 351 352 /** 353 * Creates a token that represents a double-quoted string. 354 */ 355 356 public static Token newString( String text, int startLine, int startColumn ) 357 { 358 return new Token( Types.STRING, text, startLine, startColumn ); 359 } 360 361 362 /** 363 * Creates a token that represents an identifier. 364 */ 365 366 public static Token newIdentifier( String text, int startLine, int startColumn ) 367 { 368 return new Token( Types.IDENTIFIER, text, startLine, startColumn ); 369 } 370 371 372 /** 373 * Creates a token that represents an integer. 374 */ 375 376 public static Token newInteger( String text, int startLine, int startColumn ) 377 { 378 return new Token( Types.INTEGER_NUMBER, text, startLine, startColumn ); 379 } 380 381 382 /** 383 * Creates a token that represents a decimal number. 384 */ 385 386 public static Token newDecimal( String text, int startLine, int startColumn ) 387 { 388 return new Token( Types.DECIMAL_NUMBER, text, startLine, startColumn ); 389 } 390 391 392 /** 393 * Creates a token that represents a symbol, using a library for the text. 394 */ 395 396 public static Token newSymbol( int type, int startLine, int startColumn ) 397 { 398 return new Token( type, Types.getText(type), startLine, startColumn ); 399 } 400 401 402 /** 403 * Creates a token that represents a symbol, using a library for the type. 404 */ 405 406 public static Token newSymbol( String type, int startLine, int startColumn ) 407 { 408 return new Token( Types.lookupSymbol(type), type, startLine, startColumn ); 409 } 410 411 412 /** 413 * Creates a token with the specified meaning. 414 */ 415 416 public static Token newPlaceholder( int type ) 417 { 418 Token token = new Token( Types.UNKNOWN, "", -1, -1 ); 419 token.setMeaning( type ); 420 421 return token; 422 } 423 424 }