SourceVersion.java revision 3423:d6224976006a
168651Skris/*
268651Skris * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
368651Skris * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
468651Skris *
568651Skris * This code is free software; you can redistribute it and/or modify it
668651Skris * under the terms of the GNU General Public License version 2 only, as
768651Skris * published by the Free Software Foundation.  Oracle designates this
868651Skris * particular file as subject to the "Classpath" exception as provided
968651Skris * by Oracle in the LICENSE file that accompanied this code.
1068651Skris *
1168651Skris * This code is distributed in the hope that it will be useful, but WITHOUT
1268651Skris * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1368651Skris * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1468651Skris * version 2 for more details (a copy is included in the LICENSE file that
1568651Skris * accompanied this code).
1668651Skris *
1768651Skris * You should have received a copy of the GNU General Public License version
18109998Smarkm * 2 along with this work; if not, write to the Free Software Foundation,
1968651Skris * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2068651Skris *
2168651Skris * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2268651Skris * or visit www.oracle.com if you need additional information or have any
2368651Skris * questions.
2468651Skris */
25109998Smarkm
2668651Skrispackage javax.lang.model;
2768651Skris
28109998Smarkmimport java.util.Collections;
2968651Skrisimport java.util.Set;
30109998Smarkmimport java.util.HashSet;
3168651Skris
3268651Skris/**
33109998Smarkm * Source versions of the Java™ programming language.
3468651Skris *
3568651Skris * See the appropriate edition of
36109998Smarkm * <cite>The Java&trade; Language Specification</cite>
3768651Skris * for information about a particular source version.
38109998Smarkm *
39109998Smarkm * <p>Note that additional source version constants will be added to
4068651Skris * model future releases of the language.
4168651Skris *
4268651Skris * @author Joseph D. Darcy
4368651Skris * @author Scott Seligman
4468651Skris * @author Peter von der Ah&eacute;
4568651Skris * @since 1.6
4668651Skris */
4768651Skrispublic enum SourceVersion {
4868651Skris    /*
4968651Skris     * Summary of language evolution
5068651Skris     * 1.1: nested classes
5168651Skris     * 1.2: strictfp
5268651Skris     * 1.3: no changes
5368651Skris     * 1.4: assert
5468651Skris     * 1.5: annotations, generics, autoboxing, var-args...
55109998Smarkm     * 1.6: no changes
5668651Skris     * 1.7: diamond syntax, try-with-resources, etc.
57109998Smarkm     * 1.8: lambda expressions and default methods
58109998Smarkm     *   9: modules, small cleanups to 1.7 and 1.8 changes
5968651Skris     */
6068651Skris
6168651Skris    /**
6268651Skris     * The original version.
6368651Skris     *
6468651Skris     * The language described in
6568651Skris     * <cite>The Java&trade; Language Specification, First Edition</cite>.
6668651Skris     */
6768651Skris    RELEASE_0,
6868651Skris
6968651Skris    /**
7068651Skris     * The version recognized by the Java Platform 1.1.
7168651Skris     *
7268651Skris     * The language is {@code RELEASE_0} augmented with nested classes as described in the 1.1 update to
7368651Skris     * <cite>The Java&trade; Language Specification, First Edition</cite>.
7468651Skris     */
7568651Skris    RELEASE_1,
7668651Skris
7768651Skris    /**
7868651Skris     * The version recognized by the Java 2 Platform, Standard Edition,
7968651Skris     * v 1.2.
8068651Skris     *
8168651Skris     * The language described in
8268651Skris     * <cite>The Java&trade; Language Specification,
8368651Skris     * Second Edition</cite>, which includes the {@code
8468651Skris     * strictfp} modifier.
8568651Skris     */
8668651Skris    RELEASE_2,
8768651Skris
8868651Skris    /**
8968651Skris     * The version recognized by the Java 2 Platform, Standard Edition,
9068651Skris     * v 1.3.
9168651Skris     *
9268651Skris     * No major changes from {@code RELEASE_2}.
9368651Skris     */
9468651Skris    RELEASE_3,
95109998Smarkm
9668651Skris    /**
9768651Skris     * The version recognized by the Java 2 Platform, Standard Edition,
9868651Skris     * v 1.4.
9968651Skris     *
10068651Skris     * Added a simple assertion facility.
10168651Skris     */
10268651Skris    RELEASE_4,
10368651Skris
10468651Skris    /**
10568651Skris     * The version recognized by the Java 2 Platform, Standard
10668651Skris     * Edition 5.0.
10768651Skris     *
10868651Skris     * The language described in
10968651Skris     * <cite>The Java&trade; Language Specification,
11068651Skris     * Third Edition</cite>.  First release to support
11168651Skris     * generics, annotations, autoboxing, var-args, enhanced {@code
11268651Skris     * for} loop, and hexadecimal floating-point literals.
11368651Skris     */
11468651Skris    RELEASE_5,
11568651Skris
11668651Skris    /**
11768651Skris     * The version recognized by the Java Platform, Standard Edition
11868651Skris     * 6.
11968651Skris     *
12068651Skris     * No major changes from {@code RELEASE_5}.
12168651Skris     */
12268651Skris    RELEASE_6,
12368651Skris
12468651Skris    /**
12568651Skris     * The version recognized by the Java Platform, Standard Edition
12668651Skris     * 7.
12768651Skris     *
12868651Skris     * Additions in this release include, diamond syntax for
12968651Skris     * constructors, {@code try}-with-resources, strings in switch,
13068651Skris     * binary literals, and multi-catch.
13168651Skris     * @since 1.7
13268651Skris     */
133109998Smarkm    RELEASE_7,
13468651Skris
13568651Skris    /**
13668651Skris     * The version recognized by the Java Platform, Standard Edition
13768651Skris     * 8.
13868651Skris     *
13968651Skris     * Additions in this release include lambda expressions and default methods.
14068651Skris     * @since 1.8
14168651Skris     */
14268651Skris    RELEASE_8,
14368651Skris
14468651Skris    /**
14568651Skris     * The version recognized by the Java Platform, Standard Edition
14668651Skris     * 9.
14768651Skris     *
14868651Skris     * Additions in this release include modules and removal of a
14968651Skris     * single underscore from the set of legal identifier names.
15068651Skris     *
15168651Skris     * @since 9
15268651Skris     */
15368651Skris     RELEASE_9;
15468651Skris
15568651Skris    // Note that when adding constants for newer releases, the
15668651Skris    // behavior of latest() and latestSupported() must be updated too.
15768651Skris
15868651Skris    /**
15968651Skris     * Returns the latest source version that can be modeled.
16068651Skris     *
16168651Skris     * @return the latest source version that can be modeled
16268651Skris     */
16368651Skris    public static SourceVersion latest() {
16468651Skris        return RELEASE_9;
16568651Skris    }
16668651Skris
16768651Skris    private static final SourceVersion latestSupported = getLatestSupported();
16868651Skris
16968651Skris    private static SourceVersion getLatestSupported() {
17068651Skris        try {
17168651Skris            String specVersion = System.getProperty("java.specification.version");
17268651Skris
17368651Skris            switch (specVersion) {
17468651Skris                case "9":
17568651Skris                case "1.9":
17668651Skris                    return RELEASE_9;
17768651Skris                case "1.8":
17868651Skris                    return RELEASE_8;
17968651Skris                case "1.7":
18068651Skris                    return RELEASE_7;
18168651Skris                case "1.6":
18268651Skris                    return RELEASE_6;
18368651Skris            }
18468651Skris        } catch (SecurityException se) {}
18568651Skris
18668651Skris        return RELEASE_5;
18768651Skris    }
18868651Skris
18968651Skris    /**
19068651Skris     * Returns the latest source version fully supported by the
19168651Skris     * current execution environment.  {@code RELEASE_5} or later must
19268651Skris     * be returned.
19368651Skris     *
19468651Skris     * @return the latest source version that is fully supported
19568651Skris     */
19668651Skris    public static SourceVersion latestSupported() {
19768651Skris        return latestSupported;
19868651Skris    }
199109998Smarkm
200109998Smarkm    /**
20168651Skris     * Returns whether or not {@code name} is a syntactically valid
20268651Skris     * identifier (simple name) or keyword in the latest source
20368651Skris     * version.  The method returns {@code true} if the name consists
20468651Skris     * of an initial character for which {@link
20568651Skris     * Character#isJavaIdentifierStart(int)} returns {@code true},
206109998Smarkm     * followed only by characters for which {@link
20768651Skris     * Character#isJavaIdentifierPart(int)} returns {@code true}.
20868651Skris     * This pattern matches regular identifiers, keywords, and the
20968651Skris     * literals {@code "true"}, {@code "false"}, and {@code "null"}.
21068651Skris     * The method returns {@code false} for all other strings.
21168651Skris     *
212109998Smarkm     * @param name the string to check
21368651Skris     * @return {@code true} if this string is a
21468651Skris     * syntactically valid identifier or keyword, {@code false}
21568651Skris     * otherwise.
21668651Skris     */
21768651Skris    public static boolean isIdentifier(CharSequence name) {
218109998Smarkm        String id = name.toString();
21968651Skris
22068651Skris        if (id.length() == 0) {
22168651Skris            return false;
222109998Smarkm        }
22368651Skris        int cp = id.codePointAt(0);
22468651Skris        if (!Character.isJavaIdentifierStart(cp)) {
22568651Skris            return false;
22668651Skris        }
22768651Skris        for (int i = Character.charCount(cp);
22868651Skris                i < id.length();
22968651Skris                i += Character.charCount(cp)) {
23068651Skris            cp = id.codePointAt(i);
23168651Skris            if (!Character.isJavaIdentifierPart(cp)) {
23268651Skris                return false;
23368651Skris            }
23468651Skris        }
23568651Skris        return true;
23668651Skris    }
23768651Skris
23868651Skris    /**
23968651Skris     * Returns whether or not {@code name} is a syntactically valid
24068651Skris     * qualified name in the latest source version.  Unlike {@link
24168651Skris     * #isIdentifier isIdentifier}, this method returns {@code false}
242109998Smarkm     * for keywords, boolean literals, and the null literal.
24368651Skris     *
24468651Skris     * @param name the string to check
24568651Skris     * @return {@code true} if this string is a
24668651Skris     * syntactically valid name, {@code false} otherwise.
24768651Skris     * @jls 6.2 Names and Identifiers
24868651Skris     */
24968651Skris    public static boolean isName(CharSequence name) {
25068651Skris        return isName(name, latest());
25168651Skris    }
25268651Skris
25368651Skris    /**
25468651Skris     * Returns whether or not {@code name} is a syntactically valid
25568651Skris     * qualified name in the given source version.  Unlike {@link
25668651Skris     * #isIdentifier isIdentifier}, this method returns {@code false}
25768651Skris     * for keywords, boolean literals, and the null literal.
25868651Skris     *
25968651Skris     * @param name the string to check
26068651Skris     * @param version the version to use
26168651Skris     * @return {@code true} if this string is a
26268651Skris     * syntactically valid name, {@code false} otherwise.
26368651Skris     * @jls 6.2 Names and Identifiers
26468651Skris     * @since 9
26568651Skris     */
26668651Skris    public static boolean isName(CharSequence name, SourceVersion version) {
26768651Skris        String id = name.toString();
26868651Skris
26968651Skris        for(String s : id.split("\\.", -1)) {
27068651Skris            if (!isIdentifier(s) || isKeyword(s, version))
27168651Skris                return false;
27268651Skris        }
27368651Skris        return true;
27468651Skris    }
27568651Skris
27668651Skris    /**
27768651Skris     * Returns whether or not {@code s} is a keyword, boolean literal,
27868651Skris     * or null literal in the latest source version.
27968651Skris     *
28068651Skris     * @param s the string to check
28168651Skris     * @return {@code true} if {@code s} is a keyword, or boolean
28268651Skris     * literal, or null literal, {@code false} otherwise.
28368651Skris     * @jls 3.9 Keywords
28468651Skris     * @jls 3.10.3 Boolean Literals
28568651Skris     * @jls 3.10.7 The Null Literal
28668651Skris     */
28768651Skris    public static boolean isKeyword(CharSequence s) {
28868651Skris        return isKeyword(s, latest());
28968651Skris    }
29068651Skris
29168651Skris    /**
29268651Skris     * Returns whether or not {@code s} is a keyword, boolean literal,
29368651Skris     * or null literal in the given source version.
29468651Skris     *
29568651Skris     * @param s the string to check
29668651Skris     * @param version the version to use
29768651Skris     * @return {@code true} if {@code s} is a keyword, or boolean
29868651Skris     * literal, or null literal, {@code false} otherwise.
29968651Skris     * @jls 3.9 Keywords
30068651Skris     * @jls 3.10.3 Boolean Literals
30168651Skris     * @jls 3.10.7 The Null Literal
30268651Skris     * @since 9
30368651Skris     */
304109998Smarkm    public static boolean isKeyword(CharSequence s, SourceVersion version) {
305109998Smarkm        String id = s.toString();
30668651Skris        switch(id) {
30768651Skris            // A trip through history
30868651Skris        case "strictfp":
30968651Skris            return version.compareTo(RELEASE_2) >= 0;
31068651Skris
31168651Skris        case "assert":
31268651Skris            return version.compareTo(RELEASE_4) >= 0;
31368651Skris
31468651Skris        case "enum":
31568651Skris            return version.compareTo(RELEASE_5) >= 0;
31668651Skris
31768651Skris        case "_":
31868651Skris            return version.compareTo(RELEASE_9) >= 0;
31968651Skris
32068651Skris            // Keywords common across versions
32168651Skris
32268651Skris            // Modifiers
32368651Skris        case "public":    case "protected": case "private":
32468651Skris        case "abstract":  case "static":    case "final":
32568651Skris        case "transient": case "volatile":  case "synchronized":
32668651Skris        case "native":
32768651Skris
32868651Skris            // Declarations
32968651Skris        case "class":     case "interface": case "extends":
33068651Skris        case "package":   case "throws":    case "implements":
33168651Skris
33268651Skris            // Primitive types and void
33368651Skris        case "boolean":   case "byte":      case "char":
33468651Skris        case "short":     case "int":       case "long":
33568651Skris        case "float":     case "double":
33668651Skris        case "void":
33768651Skris
33868651Skris            // Control flow
33968651Skris        case "if":      case "else":
34068651Skris        case "try":     case "catch":    case "finally":
34168651Skris        case "do":      case "while":
34268651Skris        case "for":     case "continue":
343109998Smarkm        case "switch":  case "case":     case "default":
344109998Smarkm        case "break":   case "throw":    case "return":
34568651Skris
34668651Skris            // Other keywords
34768651Skris        case  "this":   case "new":      case "super":
34868651Skris        case "import":  case "instanceof":
34968651Skris
35068651Skris            // Forbidden!
35168651Skris        case "goto":        case "const":
35268651Skris
35368651Skris            // literals
35468651Skris        case "null":         case "true":       case "false":
35568651Skris            return true;
35668651Skris
35768651Skris        default:
35868651Skris            return false;
35968651Skris        }
360109998Smarkm    }
36168651Skris}
362109998Smarkm