package bluej.parser;
import static bluej.parser.JavaErrorCodes.*;
import static bluej.parser.lexer.JavaTokenTypes.*;
import java.io.Reader;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import bluej.parser.lexer.JavaLexer;
import bluej.parser.lexer.JavaTokenFilter;
import bluej.parser.lexer.JavaTokenTypes;
import bluej.parser.lexer.LocatableToken;
| Base class for Java parsers.
|
| <p>We parse the source, and when we see certain constructs we call a corresponding method
| which subclasses can override (for instance, beginForLoop, beginForLoopBody, endForLoop).
| In general it is arranged so that a call to beginXYZ() is always followed by a call to
| endXYZ().
|
| @author Davin McCall
|
public class JavaParser
{
protected JavaTokenFilter tokenStream;
protected LocatableToken lastToken;
public static TokenStream getLexer(Reader r)
{
return new JavaLexer(r);
}
private static TokenStream getLexer(Reader r, boolean handleComments)
{
return new JavaLexer(r, handleComments);
}
private static TokenStream getLexer(Reader r, int line, int col, int pos)
{
return new JavaLexer(r, line, col, pos);
}
public JavaParser(Reader r)
{
TokenStream lexer = getLexer(r);
tokenStream = new JavaTokenFilter(lexer, this);
}
public JavaParser(Reader r, boolean handleComments)
{
TokenStream lexer = getLexer(r, handleComments);
tokenStream = new JavaTokenFilter(lexer, this);
}
public JavaParser(Reader r, int line, int col, int pos)
{
TokenStream lexer = getLexer(r, line, col, pos);
tokenStream = new JavaTokenFilter(lexer, this);
}
public JavaTokenFilter getTokenStream()
{
return tokenStream;
}
| Get the last token seen during the previous parse.
| Many parser methods return after having read a complete structure (such as a class definition). This
| method allows the retrieval of the last token which was actually part of the structure.
|
public LocatableToken getLastToken()
{
return lastToken;
}
| Signal a parse error, occurring because the next token in the token stream is
| not valid in the current context.
|
| @param msg A message/code describing the error
|
private void error(String msg)
{
errorBehind(msg, lastToken);
}
| Signal a parser error, occurring because the given token in the token stream is
| not valid in the current context, but for which a useful error diagnosis can be
| provided. The entire token will be highlighted as erroneous.
|
| @param msg A message/code describing the error
| @paran token The invalid token
|
private void error(String msg, LocatableToken token)
{
error(msg, token.getLine(), token.getColumn(), token.getEndLine(), token.getEndColumn());
}
private void errorBefore(String msg, LocatableToken token)
{
error(msg, token.getLine(), token.getColumn(), token.getLine(), token.getColumn());
}
private void errorBehind(String msg, LocatableToken token)
{
error(msg, token.getEndLine(), token.getEndColumn(), token.getEndLine(), token.getEndColumn());
}
| An error occurred during parsing. Override this method to control error behaviour.
| @param msg A message describing the error
| @param beginLine The line where the erroneous token begins
| @param beginCol The column where the erroneous token begins
| @param endLine The line where the erroneous token ends
| @param endCol The column where the erroneous token ends
|
protected void error(String msg, int beginLine, int beginCol, int endLine, int endCol)
{
throw new ParseFailure("Parse error: (" + beginLine + ":" + beginCol + ") :" + msg);
}
| Parse a compilation unit (from the beginning).
|
public void parseCU()
{
int state = 0;
while (tokenStream.LA(1).getType() != JavaTokenTypes.EOF){
if (tokenStream.LA(1).getType() == JavaTokenTypes.SEMI) {
nextToken();
continue;
}
state = parseCUpart(state);
}
finishedCU(state);
}
protected void beginPackageStatement(LocatableToken token)
{
}
| We have the package name for this source
|
protected void gotPackage(List<LocatableToken> pkgTokens)
{
}
| We've seen the semicolon at the end of a "package" statement. */
|protected void gotPackageSemi(LocatableToken token) {
}
/** Saw a modifier (public,private etc) */
protected void gotModifier(LocatableToken token) {
}
/**
* Modifiers were consumed. This is called after the entity to which the modifiers apply
| has been identified (eg gotTypeDef() called)
|
protected void modifiersConsumed()
{
}
| Beginning of some arbitrary grammatical element
|
protected void beginElement(LocatableToken token)
{
}
| End of some arbitrary grammatical element.
|
| @param token The end token
| @param included True if the end token is part of the element; false if it is part of the next element.
|
protected void endElement(LocatableToken token, boolean included)
{
}
| Got the beginning (opening brace) of a method or constructor body.
|
protected void beginMethodBody(LocatableToken token)
{
}
| End of a method or constructor body reached.
|
protected void endMethodBody(LocatableToken token, boolean included)
{
}
protected void endMethodDecl(LocatableToken token, boolean included)
{
endElement(token, included);
}
| Reached a compilation unit state.
| State 1 = package statement parsed. State 2 = one or more type definitions parsed
|
protected void reachedCUstate(int i)
{
}
| Finished parsing a compilation unit.
| @param state Our last state: see reachedCUState for details
|
protected void finishedCU(int state)
{
}
| We've seen the semicolon at the end of an "import" statement */
|protected void gotImportStmtSemi(LocatableToken token)
{
endElement(token, true);
}
protected void beginForLoop(LocatableToken token) { beginElement(token);
}
|
|protected void beginForLoopBody(LocatableToken token) {
|
|}
|
|protected void endForLoopBody(LocatableToken token, boolean included) {
|
|}
|
|protected void endForLoop(LocatableToken token, boolean included) {
|
|}
|
|protected void beginWhileLoop(LocatableToken token) {
|
|}
|
|protected void beginWhileLoopBody(LocatableToken token) {
|
|}
|
|protected void endWhileLoopBody(LocatableToken token, boolean included) {
|
|}
|
|protected void endWhileLoop(LocatableToken token, boolean included) {
|
|}
|
|protected void beginIfStmt(LocatableToken token) {
|
|}
|
|/** Begin an "if" conditional block (the part that is executed conditionally) */
protected void beginIfCondBlock(LocatableToken token) {
}
protected void endIfCondBlock(LocatableToken token, boolean included) {
|
|}
|
|protected void gotElseIf(LocatableToken token) {
|
|}
|
|protected void endIfStmt(LocatableToken token, boolean included) {
|
|}
|
|protected void beginSwitchStmt(LocatableToken token) {
|
|}
|
|protected void beginSwitchBlock(LocatableToken token) {
|
|}
|
|protected void endSwitchBlock(LocatableToken token) {
|
|}
|
|protected void endSwitchStmt(LocatableToken token, boolean included) {
|
|}
|
|protected void beginDoWhile(LocatableToken token) { beginElement(token);
|
|}
|
|protected void beginDoWhileBody(LocatableToken token) {
|
|}
|
|protected void endDoWhileBody(LocatableToken token, boolean included) {
|
|}
|
|protected void endDoWhile(LocatableToken token, boolean included) {
|
|}
|
|protected void beginTryCatchSmt(LocatableToken token, boolean hasResource) {
|
|}
|
|protected void beginTryBlock(LocatableToken token) {
|
|}
|
|protected void endTryBlock(LocatableToken token, boolean included) {
|
|}
|
|protected void endTryCatchStmt(LocatableToken token, boolean included) {
|
|}
|
|protected void beginSynchronizedBlock(LocatableToken token) {
|
|}
|
|protected void endSynchronizedBlock(LocatableToken token, boolean included) {
|
|}
|
|/** A list of a parameters to a method or constructor
protected void beginArgumentList(LocatableToken token)
{
}
| An individual argument has ended
|
protected void endArgument()
{
}
| The end of the argument list has been reached.
|
protected void endArgumentList(LocatableToken token)
{
}
| Got a "new ..." expression. Will be followed by a type spec (gotTypeSpec())
|* and possibly by array size declarations, then endExprNew()
*/
protected void gotExprNew(LocatableToken token) {
}
protected void endExprNew(LocatableToken token, boolean included) {
|
|}
|
|protected void beginArrayInitList(LocatableToken token) {
|
|}
|
|protected void endArrayInitList(LocatableToken token) {
|
|}
|
|/** An anonymous class body. Preceded by a type spec (see gotTypeSpec()) except in the case of an enum member body.
protected void beginAnonClassBody(LocatableToken token, boolean isEnumMember)
{
}
protected void endAnonClassBody(LocatableToken token, boolean included)
{
}
| Beginning of a statement block. This includes anonymous statement blocks, and static
| initializer blocks
|
protected void beginStmtblockBody(LocatableToken token)
{
beginElement(token);
}
protected void endStmtblockBody(LocatableToken token, boolean included)
{
endElement(token, included);
}
| Begin a (possibly static) initialisation block.
| @param first The first token (should be either "static" or the "{})
|* @param lcurly The "{} token which opens the block body
*/
protected void beginInitBlock(LocatableToken first, LocatableToken lcurly) {
}
/**
* End of a (possibly static) initialisation block
* @param rcurly The last token (should be "}")
* @param included True if the last token is actually a "}"
*/
protected void endInitBlock(LocatableToken rcurly, boolean included) {
}
/** Begin the type definition body. */
protected void beginTypeBody(LocatableToken leftCurlyToken) {
}
|
|/** End of type definition body. This should be a '}' unless an error occurred
protected void endTypeBody(LocatableToken endCurlyToken, boolean included)
{
}
| Got the beginning of a declaration - either a type, a field/variable, or a
| method constructor, or an initialisation block. This will be followed by one of:
|
| <ul>
| <li>gotTypeDef(...) - if a type definition
| <li>gotMethodDeclaration(...) - if a method declaration
| <li>gotConstructorDecl(...) - if a constructor declaration
| <li>beginInitBlock(...) - if an initialiser block
| <li>beginFieldDeclarations(...) - if a field declaration
| <li>beginVariableDecl(...) - if a variable declaration
| <li>endDecl(...) - if not a valid declaration
| </ul>
|
protected void gotDeclBegin(LocatableToken token)
{
beginElement(token);
}
| End a declaration (unsuccessfully).
|
protected void endDecl(LocatableToken token)
{
endElement(token, false);
}
| Called when the current element is recognised as a type definition.
| @param tdType one of TYPEDEF_CLASS, _INTERFACE, _ANNOTATION or _ENUM
|
protected void gotTypeDef(LocatableToken firstToken, int tdType)
{
}
| Called when we have the identifier token for a class/interface/enum definition
|
protected void gotTypeDefName(LocatableToken nameToken)
{
}
| Called when we have seen the "extends" literal token */
|protected void beginTypeDefExtends(LocatableToken extendsToken) {
}
/** Called after we have seen the last type in an "extends" type list */
protected void endTypeDefExtends() {
}
/** Called when we have seen the "implements" literal token */
protected void beginTypeDefImplements(LocatableToken implementsToken) {
}
/** Called after we have seen the last type in an "implements" type list */
protected void endTypeDefImplements() {
}
protected void gotTypeDefEnd(LocatableToken token, boolean included)
{
endElement(token, included);
}
/**
* Got a variable declaration, which might declare multiple variables. Each
| variable will generate gotVariable() or gotSubsequentVar().
| @param first The first token in the declaration
|
protected void beginVariableDecl(LocatableToken first)
{
}
| Got the (first) variable in a variable declaration.
| @param first The first token in the declaration
| @param idToken The token with the variable identifier
| @param inited Whether the variable is initialized as part of the declaration
|
protected void gotVariableDecl(LocatableToken first, LocatableToken idToken, boolean inited)
{
}
protected void gotSubsequentVar(LocatableToken first, LocatableToken idToken, boolean inited)
{
}
protected void endVariable(LocatableToken token, boolean included)
{
}
protected void endVariableDecls(LocatableToken token, boolean included)
{
}
protected void beginForInitDecl(LocatableToken first)
{
}
protected void gotForInit(LocatableToken first, LocatableToken idToken)
{
}
protected void gotSubsequentForInit(LocatableToken first, LocatableToken idToken, boolean initFollows)
{
}
protected void endForInit(LocatableToken token, boolean included)
{
}
protected void endForInitDecls(LocatableToken token, boolean included)
{
}
| Got a field declaration, which might declare multiple fields. Each field will generate
| gotField() or gotSubsequentField().
| @param first The first token in the declaration
|
protected void beginFieldDeclarations(LocatableToken first)
{
}
| Got a field (inside a type definition).
| @param first The first token that forms part of the field declaration
| @param idToken The token with the name of the field.
| @param initExpressionFollows
|
protected void gotField(LocatableToken first, LocatableToken idToken, boolean initExpressionFollows)
{
}
protected void gotSubsequentField(LocatableToken first, LocatableToken idToken, boolean initFollows)
{
}
| End a single field declaration (but not necessarily the field declaration statement)
|
protected void endField(LocatableToken token, boolean included)
{
}
| End a field declaration statement
|
protected void endFieldDeclarations(LocatableToken token, boolean included)
{
}
| We've seen a type specification or something that looks a lot like one.
|
protected void gotTypeSpec(List<LocatableToken> tokens)
{
}
| Seen a type cast operator. The tokens list contains the type to which is cast.
|
protected void gotTypeCast(List<LocatableToken> tokens)
{
gotTypeSpec(tokens);
}
| Saw the beginning of an expression
|
protected void beginExpression(LocatableToken token)
{
}
| Reached the end of an expression. The given token is the first one past the end.
|
protected void endExpression(LocatableToken token, boolean emptyExpression)
{
}
| Saw a literal as part of an expression
|
protected void gotLiteral(LocatableToken token)
{
}
| Saw a primitive type literal in an expression; usually occurs as "int.class"
|* or "int[].class" for example.
* @param token The primitive token
*/
protected void gotPrimitiveTypeLiteral(LocatableToken token) {
}
/** Saw an identifier as (part of) an expression */
protected void gotIdentifier(LocatableToken token) {
|
|}
|
|/**
| Got an identifier (possibly part of a compound identifier) immediately followed by
| end of input stream.
|
protected void gotIdentifierEOF(LocatableToken token)
{
gotIdentifier(token);
}
protected void gotMemberAccessEOF(LocatableToken token)
{
gotMemberAccess(token);
}
protected void gotCompoundIdent(LocatableToken token)
{
gotIdentifier(token);
}
protected void gotCompoundComponent(LocatableToken token)
{
gotMemberAccess(token);
}
protected void completeCompoundValue(LocatableToken token)
{
gotMemberAccess(token);
}
protected void completeCompoundValueEOF(LocatableToken token)
{
completeCompoundValue(token);
}
protected void completeCompoundClass(LocatableToken token)
{
gotMemberAccess(token);
}
protected void gotMemberAccess(LocatableToken token)
{
}
| Saw a member method call (expr.methodName()), token is the method name; arguments to follow
|
protected void gotMemberCall(LocatableToken token, List<LocatableToken> typeArgs)
{
}
| Saw a "naked" method call - "methodName(...)" */
|protected void gotMethodCall(LocatableToken token) {
}
/** Saw a call to the constructor as this(...) or super(...) */
protected void gotConstructorCall(LocatableToken token) {
}
|
|/** Saw a dot operator followed by end-of-file
protected void gotDotEOF(LocatableToken token)
{
gotBinaryOperator(token);
}
protected void gotStatementExpression()
{
}
protected void gotClassLiteral(LocatableToken token)
{
}
| Saw a binary operator as part of an expression
|
protected void gotBinaryOperator(LocatableToken token)
{
}
protected void gotUnaryOperator(LocatableToken token)
{
}
| Saw a "?" operator. This will be followed by the left-hand-side expression
|* (demarked by beginExpression() and endExpression(), then gotQuestionColon) followed by a continuation
* of the current expression (for the right-hand-side).
protected void gotQuestionOperator(LocatableToken token)
{
}
protected void gotQuestionColon(LocatableToken token)
{
}
| Saw the "instanceof" operator. The type spec will follow.
|*/
protected void gotInstanceOfOperator(LocatableToken token) {
}
protected void gotArrayElementAccess() {
}
protected void gotImport(List<LocatableToken> tokens, boolean isStatic, LocatableToken importToken, LocatableToken semiColonToken) {
|
|}
|
|protected void gotWildcardImport(List<LocatableToken> tokens, boolean isStatic, LocatableToken importToken, LocatableToken semiColonToken) {
|
|}
|
|/**
| We've seen a constructor declaration. The token supplied is the constructor name.
| The hiddenToken is the comment before the constructor.
|
protected void gotConstructorDecl(LocatableToken token, LocatableToken hiddenToken)
{
}
| We've seen a method declaration; the token parameter is the method name;
| the hiddenToken parameter is the comment before the method
|
protected void gotMethodDeclaration(LocatableToken token, LocatableToken hiddenToken)
{
}
| We saw a method (or constructor) parameter. The given token specifies the parameter name.
| The last type parsed by parseTypeSpec(boolean) is the parameter type, after any additonal
| array declarators (see gotArrayDeclarator()) are applied.
|
| @param token The token giving the parameter name
| @param ellipsisToken The token, if any, with the ellipsis indicating a varargs parameter. May be null.
|
protected void gotMethodParameter(LocatableToken token, LocatableToken ellipsisToken)
{
}
| Called when, after a parameter/field/variable name, array declarators "[]" are seen.
|* Will be called once for each set of "[]", immediately before gotField() or equivalent
* is called.
*/
protected void gotArrayDeclarator() {
}
/**
* Called for the array components when we get "new xyz[]".
*/
protected void gotNewArrayDeclarator(boolean withDimension) {
}
protected void gotAllMethodParameters() {
}
/**
* Saw a type parameter for a class or method. If for a method, will be bracketed by
| calls to {}code gotMethodTypeParamsBegin} and {}code endMethodTypeParams}
| @param idToken The token with the type parameter identifier
|
protected void gotTypeParam(LocatableToken idToken)
{
}
protected void gotTypeParamBound(List<LocatableToken> tokens)
{
}
protected void gotMethodTypeParamsBegin()
{
}
protected void endMethodTypeParams()
{
}
| Called by the lexer when it sees a comment.
|
public void gotComment(LocatableToken token)
{
}
| Check whether a particular token is a type declaration initiator, i.e "class", "interface"
|* or "enum"
*/
public boolean isTypeDeclarator(LocatableToken token)
{
return token.getType() == JavaTokenTypes.LITERAL_class
|| token.getType() == JavaTokenTypes.LITERAL_enum
|| token.getType() == JavaTokenTypes.LITERAL_interface;
|
|}
|
|/**
| Check whether a token is a primitive type - "int" "float" etc
|*/
public static boolean isPrimitiveType(LocatableToken token)
{
return token.getType() == JavaTokenTypes.LITERAL_void
|| token.getType() == JavaTokenTypes.LITERAL_boolean
|| token.getType() == JavaTokenTypes.LITERAL_byte
|
||| token.getType() == JavaTokenTypes.LITERAL_char
|
||| token.getType() == JavaTokenTypes.LITERAL_short
|
||| token.getType() == JavaTokenTypes.LITERAL_int
|
||| token.getType() == JavaTokenTypes.LITERAL_long
|
||| token.getType() == JavaTokenTypes.LITERAL_float
|
||| token.getType() == JavaTokenTypes.LITERAL_double;
|
|}
|
|public static final int TYPEDEF_CLASS = 0;
|
|public static final int TYPEDEF_INTERFACE = 1;
|
|public static final int TYPEDEF_ENUM = 2;
|
|public static final int TYPEDEF_ANNOTATION = 3;
|
|/** looks like a type definition, but has an error
public static final int TYPEDEF_ERROR = 4;
| doesn't parse as a type definition at all
|
public static final int TYPEDEF_EPIC_FAIL = 5;
| Get the next token from the token stream.
|
protected final LocatableToken nextToken()
{
lastToken = tokenStream.nextToken();
return lastToken;
}
public final int parseCUpart(int state)
{
LocatableToken token = nextToken();
if (token.getType() == JavaTokenTypes.LITERAL_package) {
if (state != 0) {
error("Only one 'package' statement is allowed", token);
}
token = parsePackageStmt(token);
reachedCUstate(1); state = 1;
}
else if (token.getType() == JavaTokenTypes.LITERAL_import) {
parseImportStatement(token);
reachedCUstate(1); state = 1;
}
else if (isModifier(token) || isTypeDeclarator(token)) {
gotTopLevelDecl(token);
gotDeclBegin(token);
tokenStream.pushBack(token);
parseModifiers();
parseTypeDef(token);
reachedCUstate(2); state = 2;
}
else if (token.getType() == JavaTokenTypes.EOF) {
return state;
}
else {
error("Expected: Type definition (class, interface or enum)", token);
}
return state;
}
protected void gotTopLevelDecl(LocatableToken token)
{
}
| Parse a "package xyz;"-type statement. The "package"-literal token must have already
|* been read from the token stream.
*/
public final LocatableToken parsePackageStmt(LocatableToken token)
{
beginPackageStatement(token);
token = nextToken();
|
|if (token.getType() != JavaTokenTypes.IDENT) {
|
|error("Expected identifier after 'package'");
return null;
}
List<LocatableToken> pkgTokens = parseDottedIdent(token);
gotPackage(pkgTokens);
LocatableToken lastPkgToken = lastToken;
token = nextToken();
|
|if (token.getType() != JavaTokenTypes.SEMI) {
|
|tokenStream.pushBack(token);
|
|error(BJ003, lastPkgToken.getEndLine(), lastPkgToken.getEndColumn(),
|
|lastPkgToken.getEndLine(), lastPkgToken.getEndColumn());
|
|return null;
|
|}
|
|else {
|
|gotPackageSemi(token);
|
|return token;
|
|}
|
|}
|
|/**
| Parse an import statement.
|
public void parseImportStatement()
{
LocatableToken token = nextToken();
if (token.getType() == JavaTokenTypes.LITERAL_import) {
parseImportStatement(token);
}
else {
error("Import statements must start with \"import\".");
}
}
public void parseImportStatement(final LocatableToken importToken)
{
LocatableToken token = importToken;
beginElement(token);
boolean isStatic = false;
token = tokenStream.nextToken();
if (token.getType() == JavaTokenTypes.LITERAL_static) {
isStatic = true;
token = tokenStream.nextToken();
}
if (token.getType() != JavaTokenTypes.IDENT) {
tokenStream.pushBack(token);
error("Expecting identifier (package containing element to be imported)");
endElement(token, false);
return;
}
List<LocatableToken> tokens = parseDottedIdent(token);
LocatableToken lastIdentToken = lastToken;
if (tokenStream.LA(1).getType() == JavaTokenTypes.DOT) {
LocatableToken lastToken = nextToken();
token = nextToken();
if (token.getType() == JavaTokenTypes.SEMI) {
error("Trailing '.' in import statement", lastToken.getLine(), lastToken.getColumn(),
lastToken.getEndLine(), lastToken.getEndColumn());
}
else if (token.getType() == JavaTokenTypes.STAR) {
lastToken = token;
token = nextToken();
if (token.getType() != JavaTokenTypes.SEMI) {
tokenStream.pushBack(token);
error("Expected ';' following import statement", lastToken.getEndLine(), lastToken.getEndColumn(),
lastToken.getEndLine(), lastToken.getEndColumn());
}
else {
gotWildcardImport(tokens, isStatic, importToken, token);
gotImportStmtSemi(token);
}
}
else {
error("Expected package/class identifier, or '*', in import statement.");
if (tokenStream.LA(1).getType() == JavaTokenTypes.SEMI) {
nextToken();
}
}
}
else {
token = nextToken();
if (token.getType() != JavaTokenTypes.SEMI) {
tokenStream.pushBack(token);
error("Expected ';' following import statement", lastIdentToken.getEndLine(), lastIdentToken.getEndColumn(),
lastIdentToken.getEndLine(), lastIdentToken.getEndColumn());
}
else {
gotImport(tokens, isStatic, importToken, token);
gotImportStmtSemi(token);
}
}
}
| Parse a type definition (class, interface, enum).
| Returns with {}code lastToken} set to the last token seen as part of the definition.
|
public final void parseTypeDef()
{
parseModifiers();
parseTypeDef(tokenStream.LA(1));
}
| Parse a type definition (class, interface, enum).
| Returns with {}code lastToken} set to the last token seen as part of the definition.
|
| @param firstToken the first token of the type definition, which might still be in the token
| stream, or which might be a modifier already read.
|
public final void parseTypeDef(LocatableToken firstToken)
{
int tdType = parseTypeDefBegin();
if (tdType != TYPEDEF_EPIC_FAIL) {
gotTypeDef(firstToken, tdType);
}
modifiersConsumed();
if (tdType == TYPEDEF_EPIC_FAIL) {
endDecl(tokenStream.LA(1));
return;
}
LocatableToken token = tokenStream.nextToken();
if (token.getType() != JavaTokenTypes.IDENT) {
tokenStream.pushBack(token);
gotTypeDefEnd(token, false);
error("Expected identifier (in type definition)");
return;
}
gotTypeDefName(token);
token = parseTypeDefPart2();
if (token == null) {
gotTypeDefEnd(tokenStream.LA(1), false);
return;
}
lastToken = parseTypeBody(tdType, token);
gotTypeDefEnd(lastToken, lastToken.getType() == JavaTokenTypes.RCURLY);
}
| Parse a type body. Returns the last seen token, which might be the '}' closing the
| type body or might be something else (if there is a parse error).
|
| @param tdType the type of the type definition (TYPEDEF_ constant specifying class,
| interface, enum, annotation)
| @param token the '{} token opening the type body
|
public final LocatableToken parseTypeBody(int tdType, LocatableToken token)
{
beginTypeBody(token);
if (tdType == TYPEDEF_ENUM) {
parseEnumConstants();
}
parseClassBody();
token = nextToken();
if (token.getType() != JavaTokenTypes.RCURLY) {
error("Expected '}' (in class definition)");
}
endTypeBody(token, token.getType() == JavaTokenTypes.RCURLY);
return token;
}
public final int parseTypeDefBegin()
{
parseModifiers();
LocatableToken token = nextToken();
boolean isAnnotation = token.getType() == JavaTokenTypes.AT;
if (isAnnotation) {
LocatableToken tdToken = nextToken();
if (tdToken.getType() != JavaTokenTypes.LITERAL_interface) {
error("Expected 'interface' after '@' in interface definition");
tokenStream.pushBack(tdToken);
return TYPEDEF_EPIC_FAIL;
}
token = tdToken;
}
if (isTypeDeclarator(token)) {
int tdType = -1;
if (token.getType() == JavaTokenTypes.LITERAL_class) {
tdType = TYPEDEF_CLASS;
}
else if (token.getType() == JavaTokenTypes.LITERAL_interface) {
tdType = TYPEDEF_INTERFACE;
if (isAnnotation) {
tdType = TYPEDEF_ANNOTATION;
}
}
else {
tdType = TYPEDEF_ENUM;
}
return tdType;
}
else {
error("Expected type declarator: 'class', 'interface', or 'enum'");
return TYPEDEF_EPIC_FAIL;
}
}
| Parse the part of a type definition after the name - the type parameters,
| extended classes/interfaces and implemented interfaces. Returns the '{} token
| (which begins the type definition body) on success or null on failure.
|
public LocatableToken parseTypeDefPart2()
{
LocatableToken token = nextToken();
if (token.getType() == JavaTokenTypes.LT) {
parseTypeParams();
token = tokenStream.nextToken();
}
if (token.getType() == JavaTokenTypes.LITERAL_extends) {
beginTypeDefExtends(token);
do {
parseTypeSpec(true);
token = nextToken();
}
while (token.getType() == JavaTokenTypes.COMMA){;
if (token.getType() == JavaTokenTypes.DOT) {
error("Incomplete type specificiation", token);
}
return null;
}
endTypeDefExtends();
}
if (token.getType() == JavaTokenTypes.LITERAL_implements) {
beginTypeDefImplements(token);
do {
parseTypeSpec(true);
token = nextToken();
}
while (token.getType() == JavaTokenTypes.COMMA){;
if (token.getType() == JavaTokenTypes.DOT) {
error("Incomplete type specificiation", token);
}
return null;
}
endTypeDefImplements();
}
if (token.getType() == JavaTokenTypes.LCURLY) {
return token;
}
else {
tokenStream.pushBack(token);
error("Expected '{' (in type definition)");
return null;
}
}
public void parseEnumConstants()
{
LocatableToken token = nextToken();
while (token.getType() == JavaTokenTypes.IDENT){
token = nextToken();
if (token.getType() == JavaTokenTypes.LPAREN) {
parseArgumentList(token);
token = nextToken();
}
if (token.getType() == JavaTokenTypes.LCURLY) {
beginAnonClassBody(token, true);
parseClassBody();
token = nextToken();
if (token.getType() != JavaTokenTypes.RCURLY) {
error("Expected '}' at end of enum constant body");
endAnonClassBody(token, false);
}
else {
endAnonClassBody(token, true);
token = nextToken();
}
}
if (token.getType() == JavaTokenTypes.SEMI) {
return;
}
if (token.getType() == JavaTokenTypes.RCURLY) {
tokenStream.pushBack(token);
return;
}
if (token.getType() != JavaTokenTypes.COMMA) {
error("Expecting ',' or ';' after enum constant declaration");
tokenStream.pushBack(token);
return;
}
token = nextToken();
}
}
| Parse formal type parameters. The opening '<' should have been read already.
|
public void parseTypeParams()
{
DepthRef dr = new DepthRef();
dr.depth = 1;
while (true){
LocatableToken idToken = nextToken();
if (idToken.getType() != JavaTokenTypes.IDENT) {
error("Expected identifier (in type parameter list)");
tokenStream.pushBack(idToken);
return;
}
gotTypeParam(idToken);
LocatableToken token = nextToken();
if (token.getType() == JavaTokenTypes.LITERAL_extends) {
do {
LinkedList<LocatableToken> boundTokens = new LinkedList<LocatableToken>();
if (parseTargType(false, boundTokens, dr)) {
gotTypeParamBound(boundTokens);
}
if (dr.depth <= 0) {
return;
}
token = nextToken();
} while (token.getType() == JavaTokenTypes.BAND){;
}
if (token.getType() != JavaTokenTypes.COMMA) {
if (token.getType() != JavaTokenTypes.GT) {
error("Expecting '>' at end of type parameter list");
}
tokenStream.pushBack(token);
}
break;
}
}
}
| Check whether a token represents a modifier (or an "at" symbol,
|* denoting an annotation).
*/
public static boolean isModifier(LocatableToken token)
{
int tokType = token.getType();
return (tokType == JavaTokenTypes.LITERAL_public
|
||| tokType == JavaTokenTypes.LITERAL_private
|
||| tokType == JavaTokenTypes.LITERAL_protected
|
||| tokType == JavaTokenTypes.ABSTRACT
|
||| tokType == JavaTokenTypes.FINAL
|
||| tokType == JavaTokenTypes.LITERAL_static
|
||| tokType == JavaTokenTypes.LITERAL_volatile
|
||| tokType == JavaTokenTypes.LITERAL_native
|
||| tokType == JavaTokenTypes.STRICTFP
|
||| tokType == JavaTokenTypes.LITERAL_transient
|
||| tokType == JavaTokenTypes.LITERAL_synchronized
|
||| tokType == JavaTokenTypes.AT
|
||| tokType == JavaTokenTypes.LITERAL_default);
|
|}
|
|/**
| Parse a modifier list (and return all modifier tokens in a list)
|
public List parseModifiers()
{
List<LocatableToken> rval = new LinkedList<LocatableToken>();
LocatableToken token = tokenStream.nextToken();
while (isModifier(token)){
if (token.getType() == JavaTokenTypes.AT) {
if ( tokenStream.LA(1).getType() == JavaTokenTypes.IDENT) {
lastToken = token;
parseAnnotation();
}
else {
tokenStream.pushBack(token);
return rval;
}
}
else {
gotModifier(token);
}
lastToken = token;
rval.add(token);
token = nextToken();
}
tokenStream.pushBack(token);
return rval;
}
| Having seen '{}, parse the rest of a class body.
|
public void parseClassBody()
{
LocatableToken token = tokenStream.nextToken();
while (token.getType() != JavaTokenTypes.RCURLY){
if (token.getType() == JavaTokenTypes.EOF) {
error("Unexpected end-of-file in type body; missing '}'", token);
return;
}
parseClassElement(token);
token = nextToken();
}
tokenStream.pushBack(token);
}
public final void parseClassElement(LocatableToken token)
{
if (token.getType() == JavaTokenTypes.SEMI) {
return;
}
gotDeclBegin(token);
tokenStream.pushBack(token);
LocatableToken hiddenToken = token.getHiddenBefore();
List<LocatableToken> modifiers = parseModifiers();
LocatableToken firstMod = null;
if (! modifiers.isEmpty()) {
firstMod = modifiers.get(0);
}
token = nextToken();
if (token.getType() == JavaTokenTypes.LITERAL_class
|| token.getType() == JavaTokenTypes.LITERAL_interface
|| token.getType() == JavaTokenTypes.LITERAL_enum
|| token.getType() == JavaTokenTypes.AT) {
gotInnerType(token);
tokenStream.pushBack(token);
parseTypeDef(firstMod != null ? firstMod : token);
}
else {
if (token.getType() == JavaTokenTypes.LCURLY) {
LocatableToken firstToken = firstMod == null ? token : firstMod;
beginInitBlock(firstToken, token);
modifiersConsumed();
parseStmtBlock();
token = nextToken();
if (token.getType() != JavaTokenTypes.RCURLY) {
error("Expecting '}' (at end of initialisation block)");
tokenStream.pushBack(token);
endInitBlock(token, false);
endElement(token, false);
}
else {
endInitBlock(token, true);
endElement(token, true);
}
}
else if (token.getType() == JavaTokenTypes.LT
|| token.getType() == JavaTokenTypes.IDENT
|| isPrimitiveType(token)) {
|
LocatableToken first = firstMod != null ? firstMod : token;
if (token.getType() == JavaTokenTypes.LT) {
gotMethodTypeParamsBegin();
parseTypeParams();
endMethodTypeParams();
}
else {
tokenStream.pushBack(token);
}
boolean isConstructor = tokenStream.LA(1).getType() == JavaTokenTypes.IDENT
&& tokenStream.LA(2).getType() == JavaTokenTypes.LPAREN;
if (!isConstructor && !parseTypeSpec(true)) {
endDecl(tokenStream.LA(1));
return;
}
LocatableToken idToken = tokenStream.nextToken();
if (idToken.getType() != JavaTokenTypes.IDENT) {
modifiersConsumed();
tokenStream.pushBack(idToken);
errorBefore("Expected identifier (method or field name).", idToken);
endDecl(idToken);
return;
}
token = nextToken();
int ttype = token.getType();
if (ttype == JavaTokenTypes.LBRACK || ttype == JavaTokenTypes.SEMI
|| ttype == JavaTokenTypes.ASSIGN || ttype == JavaTokenTypes.COMMA) {
|