mcimadamore@1113: /*
mcimadamore@1113: * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
mcimadamore@1113: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
mcimadamore@1113: *
mcimadamore@1113: * This code is free software; you can redistribute it and/or modify it
mcimadamore@1113: * under the terms of the GNU General Public License version 2 only, as
mcimadamore@1113: * published by the Free Software Foundation. Oracle designates this
mcimadamore@1113: * particular file as subject to the "Classpath" exception as provided
mcimadamore@1113: * by Oracle in the LICENSE file that accompanied this code.
mcimadamore@1113: *
mcimadamore@1113: * This code is distributed in the hope that it will be useful, but WITHOUT
mcimadamore@1113: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
mcimadamore@1113: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
mcimadamore@1113: * version 2 for more details (a copy is included in the LICENSE file that
mcimadamore@1113: * accompanied this code).
mcimadamore@1113: *
mcimadamore@1113: * You should have received a copy of the GNU General Public License version
mcimadamore@1113: * 2 along with this work; if not, write to the Free Software Foundation,
mcimadamore@1113: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
mcimadamore@1113: *
mcimadamore@1113: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
mcimadamore@1113: * or visit www.oracle.com if you need additional information or have any
mcimadamore@1113: * questions.
mcimadamore@1113: */
mcimadamore@1113:
mcimadamore@1113: package com.sun.tools.javac.parser;
mcimadamore@1113:
mcimadamore@1113: import java.util.Locale;
mcimadamore@1113:
mcimadamore@1113: import com.sun.tools.javac.api.Formattable;
mcimadamore@1113: import com.sun.tools.javac.api.Messages;
mcimadamore@1113: import com.sun.tools.javac.parser.Tokens.Token.Tag;
mcimadamore@1125: import com.sun.tools.javac.util.List;
mcimadamore@1113: import com.sun.tools.javac.util.Name;
mcimadamore@1113: import com.sun.tools.javac.util.Context;
mcimadamore@1125: import com.sun.tools.javac.util.ListBuffer;
mcimadamore@1113: import com.sun.tools.javac.util.Names;
mcimadamore@1113:
mcimadamore@1113: /** A class that defines codes/utilities for Java source tokens
mcimadamore@1113: * returned from lexical analysis.
mcimadamore@1113: *
mcimadamore@1113: *
This is NOT part of any supported API.
mcimadamore@1113: * If you write code that depends on this, you do so at your own risk.
mcimadamore@1113: * This code and its internal interfaces are subject to change or
mcimadamore@1113: * deletion without notice.
mcimadamore@1113: */
mcimadamore@1113: public class Tokens {
mcimadamore@1113:
mcimadamore@1113: private final Names names;
mcimadamore@1113:
mcimadamore@1113: /**
mcimadamore@1113: * Keyword array. Maps name indices to Token.
mcimadamore@1113: */
mcimadamore@1113: private final TokenKind[] key;
mcimadamore@1113:
mcimadamore@1113: /** The number of the last entered keyword.
mcimadamore@1113: */
mcimadamore@1113: private int maxKey = 0;
mcimadamore@1113:
mcimadamore@1113: /** The names of all tokens.
mcimadamore@1113: */
mcimadamore@1113: private Name[] tokenName = new Name[TokenKind.values().length];
mcimadamore@1113:
mcimadamore@1113: public static final Context.Key tokensKey =
mcimadamore@1113: new Context.Key();
mcimadamore@1113:
mcimadamore@1113: public static Tokens instance(Context context) {
mcimadamore@1113: Tokens instance = context.get(tokensKey);
mcimadamore@1113: if (instance == null)
mcimadamore@1113: instance = new Tokens(context);
mcimadamore@1113: return instance;
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: protected Tokens(Context context) {
mcimadamore@1113: context.put(tokensKey, this);
mcimadamore@1113: names = Names.instance(context);
mcimadamore@1113:
mcimadamore@1113: for (TokenKind t : TokenKind.values()) {
mcimadamore@1113: if (t.name != null)
mcimadamore@1113: enterKeyword(t.name, t);
mcimadamore@1113: else
mcimadamore@1113: tokenName[t.ordinal()] = null;
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: key = new TokenKind[maxKey+1];
mcimadamore@1113: for (int i = 0; i <= maxKey; i++) key[i] = TokenKind.IDENTIFIER;
mcimadamore@1113: for (TokenKind t : TokenKind.values()) {
mcimadamore@1113: if (t.name != null)
mcimadamore@1113: key[tokenName[t.ordinal()].getIndex()] = t;
mcimadamore@1113: }
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: private void enterKeyword(String s, TokenKind token) {
mcimadamore@1113: Name n = names.fromString(s);
mcimadamore@1113: tokenName[token.ordinal()] = n;
mcimadamore@1113: if (n.getIndex() > maxKey) maxKey = n.getIndex();
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: /**
mcimadamore@1113: * Create a new token given a name; if the name corresponds to a token name,
mcimadamore@1113: * a new token of the corresponding kind is returned; otherwise, an
mcimadamore@1113: * identifier token is returned.
mcimadamore@1113: */
mcimadamore@1113: TokenKind lookupKind(Name name) {
mcimadamore@1113: return (name.getIndex() > maxKey) ? TokenKind.IDENTIFIER : key[name.getIndex()];
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: TokenKind lookupKind(String name) {
mcimadamore@1113: return lookupKind(names.fromString(name));
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: /**
mcimadamore@1113: * This enum defines all tokens used by the javac scanner. A token is
mcimadamore@1113: * optionally associated with a name.
mcimadamore@1113: */
mcimadamore@1113: public enum TokenKind implements Formattable {
mcimadamore@1113: EOF(),
mcimadamore@1113: ERROR(),
mcimadamore@1113: IDENTIFIER(Tag.NAMED),
mcimadamore@1113: ABSTRACT("abstract"),
mcimadamore@1113: ASSERT("assert", Tag.NAMED),
mcimadamore@1113: BOOLEAN("boolean", Tag.NAMED),
mcimadamore@1113: BREAK("break"),
mcimadamore@1113: BYTE("byte", Tag.NAMED),
mcimadamore@1113: CASE("case"),
mcimadamore@1113: CATCH("catch"),
mcimadamore@1113: CHAR("char", Tag.NAMED),
mcimadamore@1113: CLASS("class"),
mcimadamore@1113: CONST("const"),
mcimadamore@1113: CONTINUE("continue"),
mcimadamore@1113: DEFAULT("default"),
mcimadamore@1113: DO("do"),
mcimadamore@1113: DOUBLE("double", Tag.NAMED),
mcimadamore@1113: ELSE("else"),
mcimadamore@1113: ENUM("enum", Tag.NAMED),
mcimadamore@1113: EXTENDS("extends"),
mcimadamore@1113: FINAL("final"),
mcimadamore@1113: FINALLY("finally"),
mcimadamore@1113: FLOAT("float", Tag.NAMED),
mcimadamore@1113: FOR("for"),
mcimadamore@1113: GOTO("goto"),
mcimadamore@1113: IF("if"),
mcimadamore@1113: IMPLEMENTS("implements"),
mcimadamore@1113: IMPORT("import"),
mcimadamore@1113: INSTANCEOF("instanceof"),
mcimadamore@1113: INT("int", Tag.NAMED),
mcimadamore@1113: INTERFACE("interface"),
mcimadamore@1113: LONG("long", Tag.NAMED),
mcimadamore@1113: NATIVE("native"),
mcimadamore@1113: NEW("new"),
mcimadamore@1113: PACKAGE("package"),
mcimadamore@1113: PRIVATE("private"),
mcimadamore@1113: PROTECTED("protected"),
mcimadamore@1113: PUBLIC("public"),
mcimadamore@1113: RETURN("return"),
mcimadamore@1113: SHORT("short", Tag.NAMED),
mcimadamore@1113: STATIC("static"),
mcimadamore@1113: STRICTFP("strictfp"),
mcimadamore@1113: SUPER("super", Tag.NAMED),
mcimadamore@1113: SWITCH("switch"),
mcimadamore@1113: SYNCHRONIZED("synchronized"),
mcimadamore@1113: THIS("this", Tag.NAMED),
mcimadamore@1113: THROW("throw"),
mcimadamore@1113: THROWS("throws"),
mcimadamore@1113: TRANSIENT("transient"),
mcimadamore@1113: TRY("try"),
mcimadamore@1113: VOID("void", Tag.NAMED),
mcimadamore@1113: VOLATILE("volatile"),
mcimadamore@1113: WHILE("while"),
mcimadamore@1113: INTLITERAL(Tag.NUMERIC),
mcimadamore@1113: LONGLITERAL(Tag.NUMERIC),
mcimadamore@1113: FLOATLITERAL(Tag.NUMERIC),
mcimadamore@1113: DOUBLELITERAL(Tag.NUMERIC),
mcimadamore@1113: CHARLITERAL(Tag.NUMERIC),
mcimadamore@1113: STRINGLITERAL(Tag.STRING),
mcimadamore@1113: TRUE("true", Tag.NAMED),
mcimadamore@1113: FALSE("false", Tag.NAMED),
mcimadamore@1113: NULL("null", Tag.NAMED),
mcimadamore@1144: ARROW("->"),
mcimadamore@1145: HASH("#"),
mcimadamore@1113: LPAREN("("),
mcimadamore@1113: RPAREN(")"),
mcimadamore@1113: LBRACE("{"),
mcimadamore@1113: RBRACE("}"),
mcimadamore@1113: LBRACKET("["),
mcimadamore@1113: RBRACKET("]"),
mcimadamore@1113: SEMI(";"),
mcimadamore@1113: COMMA(","),
mcimadamore@1113: DOT("."),
mcimadamore@1113: ELLIPSIS("..."),
mcimadamore@1113: EQ("="),
mcimadamore@1113: GT(">"),
mcimadamore@1113: LT("<"),
mcimadamore@1113: BANG("!"),
mcimadamore@1113: TILDE("~"),
mcimadamore@1113: QUES("?"),
mcimadamore@1113: COLON(":"),
mcimadamore@1113: EQEQ("=="),
mcimadamore@1113: LTEQ("<="),
mcimadamore@1113: GTEQ(">="),
mcimadamore@1113: BANGEQ("!="),
mcimadamore@1113: AMPAMP("&&"),
mcimadamore@1113: BARBAR("||"),
mcimadamore@1113: PLUSPLUS("++"),
mcimadamore@1113: SUBSUB("--"),
mcimadamore@1113: PLUS("+"),
mcimadamore@1113: SUB("-"),
mcimadamore@1113: STAR("*"),
mcimadamore@1113: SLASH("/"),
mcimadamore@1113: AMP("&"),
mcimadamore@1113: BAR("|"),
mcimadamore@1113: CARET("^"),
mcimadamore@1113: PERCENT("%"),
mcimadamore@1113: LTLT("<<"),
mcimadamore@1113: GTGT(">>"),
mcimadamore@1113: GTGTGT(">>>"),
mcimadamore@1113: PLUSEQ("+="),
mcimadamore@1113: SUBEQ("-="),
mcimadamore@1113: STAREQ("*="),
mcimadamore@1113: SLASHEQ("/="),
mcimadamore@1113: AMPEQ("&="),
mcimadamore@1113: BAREQ("|="),
mcimadamore@1113: CARETEQ("^="),
mcimadamore@1113: PERCENTEQ("%="),
mcimadamore@1113: LTLTEQ("<<="),
mcimadamore@1113: GTGTEQ(">>="),
mcimadamore@1113: GTGTGTEQ(">>>="),
mcimadamore@1113: MONKEYS_AT("@"),
mcimadamore@1113: CUSTOM;
mcimadamore@1113:
mcimadamore@1113: public final String name;
mcimadamore@1113: public final Tag tag;
mcimadamore@1113:
mcimadamore@1113: TokenKind() {
mcimadamore@1113: this(null, Tag.DEFAULT);
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: TokenKind(String name) {
mcimadamore@1113: this(name, Tag.DEFAULT);
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: TokenKind(Tag tag) {
mcimadamore@1113: this(null, tag);
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: TokenKind(String name, Tag tag) {
mcimadamore@1113: this.name = name;
mcimadamore@1113: this.tag = tag;
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: public String toString() {
mcimadamore@1113: switch (this) {
mcimadamore@1113: case IDENTIFIER:
mcimadamore@1113: return "token.identifier";
mcimadamore@1113: case CHARLITERAL:
mcimadamore@1113: return "token.character";
mcimadamore@1113: case STRINGLITERAL:
mcimadamore@1113: return "token.string";
mcimadamore@1113: case INTLITERAL:
mcimadamore@1113: return "token.integer";
mcimadamore@1113: case LONGLITERAL:
mcimadamore@1113: return "token.long-integer";
mcimadamore@1113: case FLOATLITERAL:
mcimadamore@1113: return "token.float";
mcimadamore@1113: case DOUBLELITERAL:
mcimadamore@1113: return "token.double";
mcimadamore@1113: case ERROR:
mcimadamore@1113: return "token.bad-symbol";
mcimadamore@1113: case EOF:
mcimadamore@1113: return "token.end-of-input";
mcimadamore@1113: case DOT: case COMMA: case SEMI: case LPAREN: case RPAREN:
mcimadamore@1113: case LBRACKET: case RBRACKET: case LBRACE: case RBRACE:
mcimadamore@1113: return "'" + name + "'";
mcimadamore@1113: default:
mcimadamore@1113: return name;
mcimadamore@1113: }
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: public String getKind() {
mcimadamore@1113: return "Token";
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: public String toString(Locale locale, Messages messages) {
mcimadamore@1113: return name != null ? toString() : messages.getLocalizedString(locale, "compiler.misc." + toString());
mcimadamore@1113: }
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1125: public interface Comment {
mcimadamore@1125:
mcimadamore@1125: enum CommentStyle {
mcimadamore@1125: LINE,
mcimadamore@1125: BLOCK,
mcimadamore@1125: JAVADOC,
mcimadamore@1125: }
mcimadamore@1125:
mcimadamore@1125: String getText();
mcimadamore@1125: CommentStyle getStyle();
mcimadamore@1125: boolean isDeprecated();
mcimadamore@1125: }
mcimadamore@1125:
mcimadamore@1113: /**
mcimadamore@1113: * This is the class representing a javac token. Each token has several fields
mcimadamore@1113: * that are set by the javac lexer (i.e. start/end position, string value, etc).
mcimadamore@1113: */
mcimadamore@1113: public static class Token {
mcimadamore@1113:
mcimadamore@1113: /** tags constants **/
mcimadamore@1113: enum Tag {
mcimadamore@1113: DEFAULT,
mcimadamore@1113: NAMED,
mcimadamore@1113: STRING,
mcimadamore@1113: NUMERIC;
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: /** The token kind */
mcimadamore@1113: public final TokenKind kind;
mcimadamore@1113:
mcimadamore@1113: /** The start position of this token */
mcimadamore@1113: public final int pos;
mcimadamore@1113:
mcimadamore@1113: /** The end position of this token */
mcimadamore@1113: public final int endPos;
mcimadamore@1113:
mcimadamore@1125: /** Comment reader associated with this token */
mcimadamore@1125: public final List comments;
mcimadamore@1113:
mcimadamore@1125: Token(TokenKind kind, int pos, int endPos, List comments) {
mcimadamore@1113: this.kind = kind;
mcimadamore@1113: this.pos = pos;
mcimadamore@1113: this.endPos = endPos;
mcimadamore@1125: this.comments = comments;
mcimadamore@1113: checkKind();
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: Token[] split(Tokens tokens) {
mcimadamore@1113: if (kind.name.length() < 2 || kind.tag != Tag.DEFAULT) {
mcimadamore@1113: throw new AssertionError("Cant split" + kind);
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: TokenKind t1 = tokens.lookupKind(kind.name.substring(0, 1));
mcimadamore@1113: TokenKind t2 = tokens.lookupKind(kind.name.substring(1));
mcimadamore@1113:
mcimadamore@1113: if (t1 == null || t2 == null) {
mcimadamore@1113: throw new AssertionError("Cant split - bad subtokens");
mcimadamore@1113: }
mcimadamore@1113: return new Token[] {
mcimadamore@1125: new Token(t1, pos, pos + t1.name.length(), comments),
mcimadamore@1125: new Token(t2, pos + t1.name.length(), endPos, null)
mcimadamore@1113: };
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: protected void checkKind() {
mcimadamore@1113: if (kind.tag != Tag.DEFAULT) {
mcimadamore@1113: throw new AssertionError("Bad token kind - expected " + Tag.STRING);
mcimadamore@1113: }
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: public Name name() {
mcimadamore@1113: throw new UnsupportedOperationException();
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: public String stringVal() {
mcimadamore@1113: throw new UnsupportedOperationException();
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: public int radix() {
mcimadamore@1113: throw new UnsupportedOperationException();
mcimadamore@1113: }
mcimadamore@1125:
mcimadamore@1125: /**
mcimadamore@1125: * Preserve classic semantics - if multiple javadocs are found on the token
mcimadamore@1125: * the last one is returned
mcimadamore@1125: */
mcimadamore@1125: public String comment(Comment.CommentStyle style) {
mcimadamore@1125: List readers = getReaders(Comment.CommentStyle.JAVADOC);
mcimadamore@1125: return readers.isEmpty() ?
mcimadamore@1125: null :
mcimadamore@1125: readers.head.getText();
mcimadamore@1125: }
mcimadamore@1125:
mcimadamore@1125: /**
mcimadamore@1125: * Preserve classic semantics - deprecated should be set if at least one
mcimadamore@1125: * javadoc comment attached to this token contains the '@deprecated' string
mcimadamore@1125: */
mcimadamore@1125: public boolean deprecatedFlag() {
mcimadamore@1125: for (Comment r : getReaders(Comment.CommentStyle.JAVADOC)) {
mcimadamore@1125: if (r.isDeprecated()) {
mcimadamore@1125: return true;
mcimadamore@1125: }
mcimadamore@1125: }
mcimadamore@1125: return false;
mcimadamore@1125: }
mcimadamore@1125:
mcimadamore@1125: private List getReaders(Comment.CommentStyle style) {
mcimadamore@1125: if (comments == null) {
mcimadamore@1125: return List.nil();
mcimadamore@1125: } else {
mcimadamore@1125: ListBuffer buf = ListBuffer.lb();
mcimadamore@1125: for (Comment r : comments) {
mcimadamore@1125: if (r.getStyle() == style) {
mcimadamore@1125: buf.add(r);
mcimadamore@1125: }
mcimadamore@1125: }
mcimadamore@1125: return buf.toList();
mcimadamore@1125: }
mcimadamore@1125: }
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: final static class NamedToken extends Token {
mcimadamore@1113: /** The name of this token */
mcimadamore@1113: public final Name name;
mcimadamore@1113:
mcimadamore@1125: public NamedToken(TokenKind kind, int pos, int endPos, Name name, List comments) {
mcimadamore@1125: super(kind, pos, endPos, comments);
mcimadamore@1113: this.name = name;
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: protected void checkKind() {
mcimadamore@1113: if (kind.tag != Tag.NAMED) {
mcimadamore@1113: throw new AssertionError("Bad token kind - expected " + Tag.NAMED);
mcimadamore@1113: }
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: @Override
mcimadamore@1113: public Name name() {
mcimadamore@1113: return name;
mcimadamore@1113: }
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: static class StringToken extends Token {
mcimadamore@1113: /** The string value of this token */
mcimadamore@1113: public final String stringVal;
mcimadamore@1113:
mcimadamore@1125: public StringToken(TokenKind kind, int pos, int endPos, String stringVal, List comments) {
mcimadamore@1125: super(kind, pos, endPos, comments);
mcimadamore@1113: this.stringVal = stringVal;
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: protected void checkKind() {
mcimadamore@1113: if (kind.tag != Tag.STRING) {
mcimadamore@1113: throw new AssertionError("Bad token kind - expected " + Tag.STRING);
mcimadamore@1113: }
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: @Override
mcimadamore@1113: public String stringVal() {
mcimadamore@1113: return stringVal;
mcimadamore@1113: }
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: final static class NumericToken extends StringToken {
mcimadamore@1113: /** The 'radix' value of this token */
mcimadamore@1113: public final int radix;
mcimadamore@1113:
mcimadamore@1125: public NumericToken(TokenKind kind, int pos, int endPos, String stringVal, int radix, List comments) {
mcimadamore@1125: super(kind, pos, endPos, stringVal, comments);
mcimadamore@1113: this.radix = radix;
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: protected void checkKind() {
mcimadamore@1113: if (kind.tag != Tag.NUMERIC) {
mcimadamore@1113: throw new AssertionError("Bad token kind - expected " + Tag.NUMERIC);
mcimadamore@1113: }
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: @Override
mcimadamore@1113: public int radix() {
mcimadamore@1113: return radix;
mcimadamore@1113: }
mcimadamore@1113: }
mcimadamore@1113:
mcimadamore@1113: public static final Token DUMMY =
mcimadamore@1125: new Token(TokenKind.ERROR, 0, 0, null);
mcimadamore@1113: }