All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jdk.jshell.Snippet Maven / Gradle / Ivy

There is a newer version: 9-dev-r4023-3
Show newest version
/*
 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package jdk.jshell;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static jdk.jshell.Util.REPL_CLASS_PREFIX;
import static jdk.jshell.Util.asLetters;

/**
 * A Snippet represents a snippet of Java source code as passed to
 * {@link jdk.jshell.JShell#eval}.  It is associated only with the
 * {@link jdk.jshell.JShell JShell} instance that created it.
 * An instance of Snippet (including its subclasses) is immutable: an access to
 * any of its methods will always return the same result.
 * For information about the current state of the snippet within the JShell
 * state engine, query JShell passing the Snippet.
 * 

* Because it is immutable, Snippet (and subclasses) is thread-safe. * @author Robert Field * @see jdk.jshell.JShell#status */ public abstract class Snippet { /** * Describes the general kind of snippet. * The Kind is an immutable property of a Snippet. * It is accessed with {@link jdk.jshell.Snippet#kind()}. * The Kind can be used to determine which * subclass of Snippet it is. For example, * {@link jdk.jshell.JShell#eval eval("int three() { return 3; }")} will * return a snippet creation event. The Kind of that Snippet * will be METHOD, from which you know that the subclass * of Snippet is MethodSnippet and it can be * cast as such. */ public enum Kind { /** * An import declaration: import ... * The snippet is an instance of {@link jdk.jshell.ImportSnippet}. * An import can be a single type import * ({@link jdk.jshell.Snippet.SubKind#SINGLE_TYPE_IMPORT_SUBKIND}), * a static single import * ({@link jdk.jshell.Snippet.SubKind#SINGLE_STATIC_IMPORT_SUBKIND}), * an on-demand type import * ({@link jdk.jshell.Snippet.SubKind#TYPE_IMPORT_ON_DEMAND_SUBKIND}), * or a static on-demand type import * ({@link jdk.jshell.Snippet.SubKind#SINGLE_STATIC_IMPORT_SUBKIND}) -- * use {@link jdk.jshell.Snippet#subKind()} to distinguish. * @jls 8.3: importDeclaration. */ IMPORT(true), /** * A type declaration. * Which includes: NormalClassDeclaration, EnumDeclaration, * NormalInterfaceDeclaration, and AnnotationTypeDeclaration. * The snippet is an instance of {@link jdk.jshell.TypeDeclSnippet}. * A type declaration may be an interface * {@link jdk.jshell.Snippet.SubKind#INTERFACE_SUBKIND}, * classes {@link jdk.jshell.Snippet.SubKind#CLASS_SUBKIND}, enums, and * annotation interfaces -- see {@link jdk.jshell.Snippet.SubKind} to * differentiate. * @jls 7.6: TypeDeclaration. */ TYPE_DECL(true), /** * A method declaration. * The snippet is an instance of {@link jdk.jshell.MethodSnippet}. * @jls 8.4: MethodDeclaration. */ METHOD(true), /** * One variable declaration. * Corresponding to one VariableDeclarator. * The snippet is an instance of {@link jdk.jshell.VarSnippet}. * The variable may be with or without initializer, or be a temporary * variable representing an expression -- see * {@link jdk.jshell.Snippet.SubKind}to differentiate. * @jls 8.3: FieldDeclaration. */ VAR(true), /** * An expression, with or without side-effects. * The snippet is an instance of {@link jdk.jshell.ExpressionSnippet}. * The expression is currently either a simple named reference to a * variable ({@link jdk.jshell.Snippet.SubKind#VAR_VALUE_SUBKIND}) or an * assignment (both of which have natural referencing * names) -- see {@link jdk.jshell.Snippet.SubKind} to differentiate. * @jls 15: Expression. */ EXPRESSION(false), /** * A statement. * The snippet is an instance of {@link jdk.jshell.StatementSnippet}. * @jls 14.5: Statement. */ STATEMENT(false), /** * A syntactically incorrect input for which the specific * kind could not be determined. * The snippet is an instance of {@link jdk.jshell.ErroneousSnippet}. */ ERRONEOUS(false); /** * True if this kind of snippet adds a declaration or declarations * which are visible to subsequent evaluations. */ public final boolean isPersistent; Kind(boolean isPersistent) { this.isPersistent = isPersistent; } } /** * The detailed variety of a snippet. This is a sub-classification of the * Kind. The Kind of a SubKind is accessible with * {@link jdk.jshell.Snippet.SubKind#kind}. */ public enum SubKind { /** * Single-Type-Import Declaration. * An import declaration of a single type. * @jls 7.5.1 SingleTypeImportDeclaration. */ SINGLE_TYPE_IMPORT_SUBKIND(Kind.IMPORT), /** * Type-Import-on-Demand Declaration. * A non-static "star" import. * @jls 7.5.2. TypeImportOnDemandDeclaration. */ TYPE_IMPORT_ON_DEMAND_SUBKIND(Kind.IMPORT), /** * Single-Static-Import Declaration. * An import of a static member. * @jls 7.5.3 Single-Static-Import. */ SINGLE_STATIC_IMPORT_SUBKIND(Kind.IMPORT), /** * Static-Import-on-Demand Declaration. * A static "star" import of all static members of a named type. * @jls 7.5.4. Static-Import-on-Demand Static "star" import. */ STATIC_IMPORT_ON_DEMAND_SUBKIND(Kind.IMPORT), /** * A class declaration. * A SubKind of {@link Kind#TYPE_DECL}. * @jls 8.1. NormalClassDeclaration. */ CLASS_SUBKIND(Kind.TYPE_DECL), /** * An interface declaration. * A SubKind of {@link Kind#TYPE_DECL}. * @jls 9.1. NormalInterfaceDeclaration. */ INTERFACE_SUBKIND(Kind.TYPE_DECL), /** * An enum declaration. * A SubKind of {@link Kind#TYPE_DECL}. * @jls 8.9. EnumDeclaration. */ ENUM_SUBKIND(Kind.TYPE_DECL), /** * An annotation interface declaration. A SubKind of * {@link Kind#TYPE_DECL}. * @jls 9.6. AnnotationTypeDeclaration. */ ANNOTATION_TYPE_SUBKIND(Kind.TYPE_DECL), /** * A method. The only SubKind for {@link Kind#METHOD}. * @jls 8.4. MethodDeclaration. */ METHOD_SUBKIND(Kind.METHOD), /** * A variable declaration without initializer. * A SubKind of {@link Kind#VAR}. * @jls 8.3. VariableDeclarator without VariableInitializer in * FieldDeclaration. */ VAR_DECLARATION_SUBKIND(Kind.VAR), /** * A variable declaration with an initializer expression. A * SubKind of {@link Kind#VAR}. * @jls 8.3. VariableDeclarator with VariableInitializer in * FieldDeclaration. */ VAR_DECLARATION_WITH_INITIALIZER_SUBKIND(Kind.VAR, true, true), /** * An expression whose value has been stored in a temporary variable. A * SubKind of {@link Kind#VAR}. * @jls 15. Primary. */ TEMP_VAR_EXPRESSION_SUBKIND(Kind.VAR, true, true), /** * A simple variable reference expression. A SubKind of * {@link Kind#EXPRESSION}. * @jls 15.11. Field Access as 3.8. Identifier. */ VAR_VALUE_SUBKIND(Kind.EXPRESSION, true, true), /** * An assignment expression. A SubKind of * {@link Kind#EXPRESSION}. * @jls 15.26. Assignment. */ ASSIGNMENT_SUBKIND(Kind.EXPRESSION, true, true), /** * An expression which has not been wrapped in a temporary variable * (reserved). A SubKind of {@link Kind#EXPRESSION}. */ OTHER_EXPRESSION_SUBKIND(Kind.EXPRESSION, true, true), /** * A statement. The only SubKind for {@link Kind#STATEMENT}. * @jls 14.5. Statement. */ STATEMENT_SUBKIND(Kind.STATEMENT, true, false), /** * An unknown snippet. The only SubKind for * {@link Kind#ERRONEOUS}. */ UNKNOWN_SUBKIND(Kind.ERRONEOUS, false, false); private final boolean isExecutable; private final boolean hasValue; private final Kind kind; SubKind(Kind kind) { this.kind = kind; this.isExecutable = false; this.hasValue = false; } SubKind(Kind kind, boolean isExecutable, boolean hasValue) { this.kind = kind; this.isExecutable = isExecutable; this.hasValue = hasValue; } /** * Is this SubKind executable? * * @return true if this SubKind can be executed. */ public boolean isExecutable() { return isExecutable; } /** * Is this SubKind executable and is non-void. * * @return true if this SubKind has a value. */ public boolean hasValue() { return hasValue; } /** * The {@link Snippet.Kind} that corresponds to this SubKind. * * @return the fixed Kind for this SubKind */ public Kind kind() { return kind; } } /** * Describes the current state of a Snippet. * This is a dynamic property of a Snippet within the JShell state -- * thus is retrieved with a {@linkplain * jdk.jshell.JShell#status(jdk.jshell.Snippet) query on JShell}. *

* The Status changes as the state changes. * For example, creation of another snippet with * {@link jdk.jshell.JShell#eval(java.lang.String) eval} * may resolve dependencies of this Snippet (or invalidate those dependencies), or * {@linkplain jdk.jshell.Snippet.Status#OVERWRITTEN overwrite} * this Snippet changing its * Status. *

* Important properties associated with Status are: * {@link jdk.jshell.Snippet.Status#isDefined}, if it is visible to other * existing and new snippets; and * {@link jdk.jshell.Snippet.Status#isActive}, if, as the * JShell state changes, the snippet will update, possibly * changing Status. * An executable Snippet can only be executed if it is in the the * {@link jdk.jshell.Snippet.Status#VALID} Status. * @see JShell#status(jdk.jshell.Snippet) */ public enum Status { /** * The snippet is a valid snippet * (in the context of current JShell state). * Only snippets with VALID * Status can be executed (though not all * VALID snippets have executable code). * If the snippet is a declaration or import, it is visible to other * snippets ({@link Status#isDefined isDefined} == true). *

* The snippet will update as dependents change * ({@link Status#isActive isActive} == true), its * status could become RECOVERABLE_DEFINED, RECOVERABLE_NOT_DEFINED, * DROPPED, or OVERWRITTEN. */ VALID(true, true), /** * The snippet is a declaration snippet with potentially recoverable * unresolved references or other issues in its body * (in the context of current JShell state). * Only a {@link jdk.jshell.DeclarationSnippet} can have this * Status. * The snippet has a valid signature and it is visible to other * snippets ({@link Status#isDefined isDefined} == true) * and thus can be referenced in existing or new snippets * but the snippet cannot be executed. * An {@link UnresolvedReferenceException} will be thrown on an attempt * to execute it. *

* The snippet will update as dependents change * ({@link Status#isActive isActive} == true), its * status could become VALID, RECOVERABLE_NOT_DEFINED, * DROPPED, or OVERWRITTEN. *

* Note: both RECOVERABLE_DEFINED and RECOVERABLE_NOT_DEFINED * indicate potentially recoverable errors, they differ in that, for * RECOVERABLE_DEFINED, the snippet is * {@linkplain Status#isDefined defined}. */ RECOVERABLE_DEFINED(true, true), /** * The snippet is a declaration snippet with potentially recoverable * unresolved references or other issues * (in the context of current JShell state). * Only a {@link jdk.jshell.DeclarationSnippet} can have this * Status. * The snippet has an invalid signature or the implementation is * otherwise unable to define it. * The snippet it is not visible to other snippets * ({@link Status#isDefined isDefined} == false) * and thus cannot be referenced or executed. *

* The snippet will update as dependents change * ({@link Status#isActive isActive} == true), its * status could become VALID, RECOVERABLE_DEFINED, * DROPPED, or OVERWRITTEN. *

* Note: both RECOVERABLE_DEFINED and RECOVERABLE_NOT_DEFINED * indicate potentially recoverable errors, they differ in that, for * RECOVERABLE_DEFINED, the snippet is * {@linkplain Status#isDefined defined}. */ RECOVERABLE_NOT_DEFINED(true, false), /** * The snippet is inactive because of an explicit call to * the {@link JShell#drop(jdk.jshell.PersistentSnippet)}. * Only a {@link jdk.jshell.PersistentSnippet} can have this * Status. * The snippet is not visible to other snippets * ({@link Status#isDefined isDefined} == false) * and thus cannot be referenced or executed. *

* The snippet will not update as dependents change * ({@link Status#isActive isActive} == false), its * Status will never change again. */ DROPPED(false, false), /** * The snippet is inactive because it has been replaced by a new * snippet. This occurs when the new snippet added with * {@link jdk.jshell.JShell#eval} matches a previous snippet. * A TypeDeclSnippet will match another * TypeDeclSnippet if the names match. * For example class X { } will overwrite * class X { int ii; } or * interface X { }. * A MethodSnippet will match another * MethodSnippet if the names and parameter types * match. * For example void m(int a) { } will overwrite * int m(int a) { return a+a; }. * A VarSnippet will match another * VarSnippet if the names match. * For example double z; will overwrite * long z = 2L;. * Only a {@link jdk.jshell.PersistentSnippet} can have this * Status. * The snippet is not visible to other snippets * ({@link Status#isDefined isDefined} == false) * and thus cannot be referenced or executed. *

* The snippet will not update as dependents change * ({@link Status#isActive isActive} == false), its * Status will never change again. */ OVERWRITTEN(false, false), /** * The snippet is inactive because it failed compilation on initial * evaluation and it is not capable of becoming valid with further * changes to the JShell state. * The snippet is not visible to other snippets * ({@link Status#isDefined isDefined} == false) * and thus cannot be referenced or executed. *

* The snippet will not update as dependents change * ({@link Status#isActive isActive} == false), its * Status will never change again. */ REJECTED(false, false), /** * The snippet is inactive because it does not yet exist. * Used only in {@link SnippetEvent#previousStatus} for new * snippets. * {@link jdk.jshell.JShell#status(jdk.jshell.Snippet) JShell.status(Snippet)} * will never return this Status. * Vacuously, {@link Status#isDefined isDefined} and * {@link Status#isActive isActive} are both defined false. */ NONEXISTENT(false, false); /** * Is the Snippet active, that is, will the snippet * be re-evaluated when a new * {@link JShell#eval(java.lang.String) JShell.eval(String)} or * {@link JShell#drop(jdk.jshell.PersistentSnippet) * JShell.drop(PersistentSnippet)} that could change * its status is invoked? This is more broad than * {@link Status#isDefined} since a Snippet which is * {@link Status#RECOVERABLE_NOT_DEFINED} * will be updated. */ public final boolean isActive; /** * Is the snippet currently part of the defined state of the JShell? * Is it visible to compilation of other snippets? */ public final boolean isDefined; Status(boolean isActive, boolean isDefined) { this.isActive = isActive; this.isDefined = isDefined; } } private final Key key; private final String source; private final Wrap guts; final String unitName; private final SubKind subkind; private int seq; private String className; private String id; private OuterWrap outer; private Status status; private List unresolved; private DiagList diagnostics; Snippet(Key key, String userSource, Wrap guts, String unitName, SubKind subkind) { this.key = key; this.source = userSource; this.guts = guts; this.unitName = unitName; this.subkind = subkind; this.status = Status.NONEXISTENT; setSequenceNumber(0); } /**** public access ****/ /** * The unique identifier for the snippet. No two active snippets will have * the same id(). * @return the snippet id string. */ public String id() { return id; } /** * The {@link jdk.jshell.Snippet.Kind} for the snippet. * Indicates the subclass of Snippet. * @return the Kind of the snippet * @see Snippet.Kind */ public Kind kind() { return subkind.kind(); } /** * Return the {@link SubKind} of snippet. * The SubKind is useful for feedback to users. * @return the SubKind corresponding to this snippet */ public SubKind subKind() { return subkind; } /** * Return the source code of the snippet. * @return the source code corresponding to this snippet */ public String source() { return source; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Snippet:"); if (key() != null) { sb.append(key().toString()); } sb.append('-'); sb.append(source); return sb.toString(); } //**** internal access **** String name() { return unitName; } Key key() { return key; } List unresolved() { return Collections.unmodifiableList(unresolved); } DiagList diagnostics() { return diagnostics; } /** * @return the corralled guts */ Wrap corralled() { return null; } Collection declareReferences() { return null; } Collection bodyReferences() { return null; } String importLine(JShell state) { return ""; } void setId(String id) { this.id = id; } final void setSequenceNumber(int seq) { this.seq = seq; this.className = REPL_CLASS_PREFIX + key().index() + asLetters(seq); } void setOuterWrap(OuterWrap outer) { this.outer = outer; } void setCompilationStatus(Status status, List unresolved, DiagList diagnostics) { this.status = status; this.unresolved = unresolved; this.diagnostics = diagnostics; } void setDiagnostics(DiagList diagnostics) { this.diagnostics = diagnostics; } void setFailed(DiagList diagnostics) { this.seq = -1; this.outer = null; this.status = Status.REJECTED; this.unresolved = Collections.emptyList(); this.diagnostics = diagnostics; } void setDropped() { this.status = Status.DROPPED; } void setOverwritten() { this.status = Status.OVERWRITTEN; } Status status() { return status; } String className() { return className; } /** * Top-level wrap * @return */ OuterWrap outerWrap() { return outer; } /** * Basically, class version for this Key. * @return int */ int sequenceNumber() { return seq; } Wrap guts() { return guts; } boolean isExecutable() { return subkind.isExecutable(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy