import antlr.CommonToken;
/**
* This is a token class which can keep track of full extent information.
* That is, it knows about end positions as well as start positions and the
* file (name) of origin of a token. Note that, conforming to standard Java
* usage, the end column value is numerically one more than the actual end
* column position, making (end column - start column) be the length of the
* token, if it is on a single line, and allowing for the possibility of
* 0-length tokens. If, for some reason, a start or end position hasn't
* been calculated for an instance, it will return 0 from the
* accessors in question. Since valid line and column nubmers start at
* 1, it is thus possible to distinguish these from all
* legitimately set values.
*
*
This file is in the public domain.
* * @author Dan Bornstein, danfuzz@milk.com */ public class ExtentToken extends CommonToken { /** the end line of the token */ protected int endLine; /** the end column of the token (+1, see discussion in the header) */ protected int endCol; /** null-ok; the file (name) of origin of the token */ protected String fileName; // ------------------------------------------------------------------------ // constructors /** * Construct an instance. The instance will be of type {@link * #INVALID_TYPE}, have empty ("", not null)
* text, have 0 for all position values, and have a
* null file name.
*/
public ExtentToken ()
{
this ("");
}
/**
* Construct an instance with the given text. The instance will be of
* type {@link #INVALID_TYPE}, have 0 for all position
* values, and have a null file name.
*
* @param text null-ok; the token text
*/
public ExtentToken (String text)
{
this (INVALID_TYPE, text);
}
/**
* Construct an instance with the given type and text. The instance
* will have 0 for all position values and have a
* null file name.
*
* @param type the token type
* @param text null-ok; the token text
*/
public ExtentToken (int type, String text)
{
super (type, text);
line = 0;
col = 0;
endLine = 0;
endCol = 0;
fileName = null;
}
// ------------------------------------------------------------------------
// public instance methods
/**
* Return the extent of this token as a formatted string. The form
* is identical to the form used in the front of Caml error messages
* (which the emacs error parser understands):
*
* File "file-name", line[s]
* start[-end], character[s]
* start[-end]
*
* @return the extent string for this instance
*/
public String extentString ()
{
StringBuffer sb = new StringBuffer (100);
sb.append ("File ");
if (fileName != null)
{
sb.append ('\"');
sb.append (fileName);
sb.append ('\"');
}
else
{
sb.append ("0 position values, and, if no end position is defined
* in any of the consulted nodes, it will set the end position of this
* instance to be the same as the start position. This method uses the
* position variables of this instance during the tree walk, so it is
* unwise to use an instance which is pointed at by the given AST.
*
* @param ast the tree to figure out the extent of
*/
public void setFromTokenAST (TokenAST ast)
{
line = Integer.MAX_VALUE;
col = Integer.MAX_VALUE;
endLine = Integer.MIN_VALUE;
endCol = Integer.MIN_VALUE;
fileName = null;
setFromTokenAST (this, ast);
if (line == Integer.MAX_VALUE)
{
line = 0;
col = 0;
}
else if (col == Integer.MAX_VALUE)
{
col = 0;
}
if (endLine == Integer.MIN_VALUE)
{
endLine = line;
endCol = col;
}
else if (endCol == Integer.MIN_VALUE)
{
endCol = 0;
}
}
// ------------------------------------------------------------------------
// private static methods
/**
* Helper method for figuring out the extent of an AST. This is called
* by the public method of the same name, and it will in turn call itself
* recursively.
*
* @param result non-null; the token to destructively modify as the
* result of the operation
* @param ast non-null; the tree to walk
*/
static private void setFromTokenAST (ExtentToken result, TokenAST ast)
{
ExtentToken tok = (ExtentToken) ast.getToken ();
if (tok != null)
{
int line = tok.getLine ();
if (line != 0)
{
int col = tok.getColumn ();
int minLine = result.getLine ();
int minCol = result.getColumn ();
if (line < minLine)
{
result.setLine (line);
result.setColumn (col);
result.setFileName (tok.getFileName ());
}
else if ((line == minLine) && (col < minCol))
{
result.setColumn (col);
result.setFileName (tok.getFileName ());
}
}
int endLine = tok.getEndLine ();
if (endLine != 0)
{
int endCol = tok.getEndColumn ();
int maxLine = result.getEndLine ();
int maxCol = result.getEndColumn ();
if (endLine > maxLine)
{
result.setEndLine (endLine);
result.setEndColumn (endCol);
}
else if ((endLine == maxLine) && (endCol > maxCol))
{
result.setEndColumn (endCol);
}
}
}
ast = (TokenAST) ast.getFirstChild ();
while (ast != null)
{
setFromTokenAST (result, ast);
ast = (TokenAST) ast.getNextSibling ();
}
}
}