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: }