001: /*
002: $Id: Token.java 4032 2006-08-30 07:18:49Z mguillem $
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: * A <code>CSTNode</code> produced by the <code>Lexer</code>.
053: *
054: * @see antlr.Parser
055: * @see antlr.Token
056: * @see Reduction
057: * @see Types
058: *
059: * @author <a href="mailto:bob@werken.com">bob mcwhirter</a>
060: * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
061: *
062: * @version $Id: Token.java 4032 2006-08-30 07:18:49Z mguillem $
063: */
064:
065: public class Token extends CSTNode {
066: public static final Token NULL = new Token();
067: public static final Token EOF = new Token(Types.EOF, "", -1, -1);
068:
069: //---------------------------------------------------------------------------
070: // TOKEN INITIALIZATION AND SUCH
071:
072: private int type = Types.UNKNOWN; // the actual type identified by the lexer
073: private int meaning = Types.UNKNOWN; // an interpretation applied to the token after the fact
074:
075: private String text = ""; // the text of the token
076: private int startLine = -1; // the source line on which the token begins
077: private int startColumn = -1; // the source column on which the token begins
078:
079: /**
080: * Initializes the Token with the specified information.
081: */
082:
083: public Token(int type, String text, int startLine, int startColumn) {
084: this .type = type;
085: this .meaning = type;
086: this .text = text;
087: this .startLine = startLine;
088: this .startColumn = startColumn;
089: }
090:
091: /**
092: * Initializes the NULL Token.
093: */
094:
095: private Token() {
096: }
097:
098: /**
099: * Returns a copy of this Token.
100: */
101:
102: public Token dup() {
103: Token token = new Token(this .type, this .text, this .startLine,
104: this .startColumn);
105: token.setMeaning(this .meaning);
106:
107: return token;
108: }
109:
110: //---------------------------------------------------------------------------
111: // NODE IDENTIFICATION AND MEANING
112:
113: /**
114: * Returns the meaning of this node. If the node isEmpty(), returns
115: * the type of Token.NULL.
116: */
117:
118: public int getMeaning() {
119: return meaning;
120: }
121:
122: /**
123: * Sets the meaning for this node (and it's root Token). Not
124: * valid if the node isEmpty(). Returns this token, for
125: * convenience.
126: */
127:
128: public CSTNode setMeaning(int meaning) {
129: this .meaning = meaning;
130: return this ;
131: }
132:
133: /**
134: * Returns the actual type of the node. If the node isEmpty(), returns
135: * the type of Token.NULL.
136: */
137:
138: public int getType() {
139: return type;
140: }
141:
142: //---------------------------------------------------------------------------
143: // MEMBER ACCESS
144:
145: /**
146: * Returns the number of elements in the node (including root).
147: */
148:
149: public int size() {
150: return 1;
151: }
152:
153: /**
154: * Returns the specified element, or null.
155: */
156:
157: public CSTNode get(int index) {
158: if (index > 0) {
159: throw new GroovyBugError(
160: "attempt to access Token element other than root");
161: }
162:
163: return this ;
164: }
165:
166: /**
167: * Returns the root of the node. By convention, all nodes have
168: * a Token as the first element (or root), which indicates the type
169: * of the node. May return null if the node <code>isEmpty()</code>.
170: */
171:
172: public Token getRoot() {
173: return this ;
174: }
175:
176: /**
177: * Returns the text of the root node. Uses <code>getRoot(true)</code>
178: * to get the root, so you will only receive null in return if the
179: * root token returns it.
180: */
181:
182: public String getRootText() {
183: return text;
184: }
185:
186: /**
187: * Returns the text of the token. Equivalent to
188: * <code>getRootText()</code> when called directly.
189: */
190:
191: public String getText() {
192: return text;
193: }
194:
195: /**
196: * Not advisable, but if you need to adjust the token's text, this
197: * will do it.
198: */
199:
200: public void setText(String text) {
201: this .text = text;
202: }
203:
204: /**
205: * Returns the starting line of the node. Returns -1
206: * if not known.
207: */
208:
209: public int getStartLine() {
210: return startLine;
211: }
212:
213: /**
214: * Returns the starting column of the node. Returns -1
215: * if not known.
216: */
217:
218: public int getStartColumn() {
219: return startColumn;
220: }
221:
222: //---------------------------------------------------------------------------
223: // OPERATIONS
224:
225: /**
226: * Creates a <code>Reduction</code> from this token. Returns self if the
227: * node is already a <code>Reduction</code>.
228: */
229:
230: public Reduction asReduction() {
231: return new Reduction(this );
232: }
233:
234: /**
235: * Creates a <code>Reduction</code> from this token, adding the supplied
236: * node as the second element.
237: */
238:
239: public Reduction asReduction(CSTNode second) {
240: Reduction created = asReduction();
241: created.add(second);
242: return created;
243: }
244:
245: /**
246: * Creates a <code>Reduction</code> from this token, adding the supplied
247: * nodes as the second and third element, respectively.
248: */
249:
250: public Reduction asReduction(CSTNode second, CSTNode third) {
251: Reduction created = asReduction(second);
252: created.add(third);
253: return created;
254: }
255:
256: /**
257: * Creates a <code>Reduction</code> from this token, adding the supplied
258: * nodes as the second, third, and fourth element, respectively.
259: */
260:
261: public Reduction asReduction(CSTNode second, CSTNode third,
262: CSTNode fourth) {
263: Reduction created = asReduction(second, third);
264: created.add(fourth);
265: return created;
266: }
267:
268: //---------------------------------------------------------------------------
269: // TOKEN FACTORIES
270:
271: /**
272: * Creates a token that represents a keyword. Returns null if the
273: * specified text isn't a keyword.
274: */
275:
276: public static Token newKeyword(String text, int startLine,
277: int startColumn) {
278:
279: int type = Types.lookupKeyword(text);
280: if (type != Types.UNKNOWN) {
281: return new Token(type, text, startLine, startColumn);
282: }
283:
284: return null;
285:
286: }
287:
288: /**
289: * Creates a token that represents a double-quoted string.
290: */
291:
292: public static Token newString(String text, int startLine,
293: int startColumn) {
294: return new Token(Types.STRING, text, startLine, startColumn);
295: }
296:
297: /**
298: * Creates a token that represents an identifier.
299: */
300:
301: public static Token newIdentifier(String text, int startLine,
302: int startColumn) {
303: return new Token(Types.IDENTIFIER, text, startLine, startColumn);
304: }
305:
306: /**
307: * Creates a token that represents an integer.
308: */
309:
310: public static Token newInteger(String text, int startLine,
311: int startColumn) {
312: return new Token(Types.INTEGER_NUMBER, text, startLine,
313: startColumn);
314: }
315:
316: /**
317: * Creates a token that represents a decimal number.
318: */
319:
320: public static Token newDecimal(String text, int startLine,
321: int startColumn) {
322: return new Token(Types.DECIMAL_NUMBER, text, startLine,
323: startColumn);
324: }
325:
326: /**
327: * Creates a token that represents a symbol, using a library for the text.
328: */
329:
330: public static Token newSymbol(int type, int startLine,
331: int startColumn) {
332: return new Token(type, Types.getText(type), startLine,
333: startColumn);
334: }
335:
336: /**
337: * Creates a token that represents a symbol, using a library for the type.
338: */
339:
340: public static Token newSymbol(String type, int startLine,
341: int startColumn) {
342: return new Token(Types.lookupSymbol(type), type, startLine,
343: startColumn);
344: }
345:
346: /**
347: * Creates a token with the specified meaning.
348: */
349:
350: public static Token newPlaceholder(int type) {
351: Token token = new Token(Types.UNKNOWN, "", -1, -1);
352: token.setMeaning(type);
353:
354: return token;
355: }
356:
357: }
|