Snippet.java revision 3357:3e3553ee39d9
1/*
2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.jshell;
27
28import java.util.Collection;
29import java.util.Collections;
30import java.util.List;
31
32/**
33 * A Snippet represents a snippet of Java source code as passed to
34 * {@link jdk.jshell.JShell#eval}.  It is associated only with the
35 * {@link jdk.jshell.JShell JShell} instance that created it.
36 * An instance of Snippet (including its subclasses) is immutable: an access to
37 * any of its methods will always return the same result.
38 * For information about the current state of the snippet within the JShell
39 * state engine, query <code>JShell</code> passing the Snippet.
40 * <p>
41 * Because it is immutable, <code>Snippet</code> (and subclasses) is thread-safe.
42 * @author Robert Field
43 * @see jdk.jshell.JShell#status
44 */
45public abstract class Snippet {
46
47    /**
48     * Describes the general kind of snippet.
49     * The <code>Kind</code> is an immutable property of a Snippet.
50     * It is accessed with {@link jdk.jshell.Snippet#kind()}.
51     * The <code>Kind</code> can be used to determine which
52     * subclass of Snippet it is. For example,
53     * {@link jdk.jshell.JShell#eval eval("int three() { return 3; }")} will
54     * return a snippet creation event.  The <code>Kind</code> of that Snippet
55     * will be <code>METHOD</code>, from which you know that the subclass
56     * of <code>Snippet</code> is <code>MethodSnippet</code> and it can be
57     * cast as such.
58     */
59    public enum Kind {
60        /**
61         * An import declaration: <code>import</code> ...
62         * The snippet is an instance of {@link jdk.jshell.ImportSnippet}.
63         * An import can be a single type import
64         * ({@link jdk.jshell.Snippet.SubKind#SINGLE_TYPE_IMPORT_SUBKIND}),
65         * a static single import
66         * ({@link jdk.jshell.Snippet.SubKind#SINGLE_STATIC_IMPORT_SUBKIND}),
67         * an on-demand type import
68         * ({@link jdk.jshell.Snippet.SubKind#TYPE_IMPORT_ON_DEMAND_SUBKIND}),
69         * or a static on-demand type import
70         * ({@link jdk.jshell.Snippet.SubKind#SINGLE_STATIC_IMPORT_SUBKIND}) --
71         * use {@link jdk.jshell.Snippet#subKind()} to distinguish.
72         * @jls 8.3: importDeclaration.
73         */
74        IMPORT(true),
75
76        /**
77         * A type declaration.
78         * Which includes: NormalClassDeclaration, EnumDeclaration,
79         * NormalInterfaceDeclaration, and AnnotationTypeDeclaration.
80         * The snippet is an instance of {@link jdk.jshell.TypeDeclSnippet}.
81         * A type declaration may be an interface
82         * {@link jdk.jshell.Snippet.SubKind#INTERFACE_SUBKIND},
83         * classes {@link jdk.jshell.Snippet.SubKind#CLASS_SUBKIND}, enums, and
84         * annotation interfaces -- see {@link jdk.jshell.Snippet.SubKind} to
85         * differentiate.
86         * @jls 7.6: TypeDeclaration.
87         */
88        TYPE_DECL(true),
89
90        /**
91         * A method declaration.
92         * The snippet is an instance of {@link jdk.jshell.MethodSnippet}.
93         * @jls 8.4: MethodDeclaration.
94         */
95        METHOD(true),
96
97        /**
98         * One variable declaration.
99         * Corresponding to one <i>VariableDeclarator</i>.
100         * The snippet is an instance of {@link jdk.jshell.VarSnippet}.
101         * The variable may be with or without initializer, or be a temporary
102         * variable representing an expression -- see
103         * {@link jdk.jshell.Snippet.SubKind}to differentiate.
104         * @jls 8.3: FieldDeclaration.
105         */
106        VAR(true),
107
108        /**
109         * An expression, with or without side-effects.
110         * The snippet is an instance of {@link jdk.jshell.ExpressionSnippet}.
111         * The expression is currently either a simple named reference to a
112         * variable ({@link jdk.jshell.Snippet.SubKind#VAR_VALUE_SUBKIND}) or an
113         * assignment (both of which have natural referencing
114         * names) -- see {@link jdk.jshell.Snippet.SubKind} to differentiate.
115         * @jls 15: Expression.
116         */
117        EXPRESSION(false),
118
119        /**
120         * A statement.
121         * The snippet is an instance of {@link jdk.jshell.StatementSnippet}.
122         * @jls 14.5: Statement.
123         */
124        STATEMENT(false),
125
126        /**
127         * A syntactically incorrect input for which the specific
128         * kind could not be determined.
129         * The snippet is an instance of {@link jdk.jshell.ErroneousSnippet}.
130         */
131        ERRONEOUS(false);
132
133        /**
134         * True if this kind of snippet adds a declaration or declarations
135         * which are visible to subsequent evaluations.
136         */
137        public final boolean isPersistent;
138
139        Kind(boolean isPersistent) {
140            this.isPersistent = isPersistent;
141        }
142    }
143
144    /**
145     * The detailed variety of a snippet.  This is a sub-classification of the
146     * Kind.  The Kind of a SubKind is accessible with
147     * {@link jdk.jshell.Snippet.SubKind#kind}.
148     */
149    public enum SubKind {
150
151        /**
152         * Single-Type-Import Declaration.
153         * An import declaration of a single type.
154         * @jls 7.5.1 SingleTypeImportDeclaration.
155         */
156        SINGLE_TYPE_IMPORT_SUBKIND(Kind.IMPORT),
157
158        /**
159         * Type-Import-on-Demand Declaration.
160         * A non-static "star" import.
161         * @jls 7.5.2. TypeImportOnDemandDeclaration.
162         */
163        TYPE_IMPORT_ON_DEMAND_SUBKIND(Kind.IMPORT),
164
165        /**
166         * Single-Static-Import Declaration.
167         * An import of a static member.
168         * @jls 7.5.3 Single-Static-Import.
169         */
170        SINGLE_STATIC_IMPORT_SUBKIND(Kind.IMPORT),
171
172        /**
173         * Static-Import-on-Demand Declaration.
174         * A static "star" import of all static members of a named type.
175         * @jls 7.5.4. Static-Import-on-Demand Static "star" import.
176         */
177        STATIC_IMPORT_ON_DEMAND_SUBKIND(Kind.IMPORT),
178
179        /**
180         * A class declaration.
181         * A <code>SubKind</code> of {@link Kind#TYPE_DECL}.
182         * @jls 8.1. NormalClassDeclaration.
183         */
184        CLASS_SUBKIND(Kind.TYPE_DECL),
185
186        /**
187         * An interface declaration.
188         * A <code>SubKind</code> of {@link Kind#TYPE_DECL}.
189         * @jls 9.1. NormalInterfaceDeclaration.
190         */
191        INTERFACE_SUBKIND(Kind.TYPE_DECL),
192
193        /**
194         * An enum declaration.
195         * A <code>SubKind</code> of {@link Kind#TYPE_DECL}.
196         * @jls 8.9. EnumDeclaration.
197         */
198        ENUM_SUBKIND(Kind.TYPE_DECL),
199
200        /**
201         * An annotation interface declaration. A <code>SubKind</code> of
202         * {@link Kind#TYPE_DECL}.
203         * @jls 9.6. AnnotationTypeDeclaration.
204         */
205        ANNOTATION_TYPE_SUBKIND(Kind.TYPE_DECL),
206
207        /**
208         * A method. The only <code>SubKind</code> for {@link Kind#METHOD}.
209         * @jls 8.4. MethodDeclaration.
210         */
211        METHOD_SUBKIND(Kind.METHOD),
212
213        /**
214         * A variable declaration without initializer.
215         * A <code>SubKind</code> of {@link Kind#VAR}.
216         * @jls 8.3. VariableDeclarator without VariableInitializer in
217         * FieldDeclaration.
218         */
219        VAR_DECLARATION_SUBKIND(Kind.VAR),
220
221        /**
222         * A variable declaration with an initializer expression. A
223         * <code>SubKind</code> of {@link Kind#VAR}.
224         * @jls 8.3. VariableDeclarator with VariableInitializer in
225         * FieldDeclaration.
226         */
227        VAR_DECLARATION_WITH_INITIALIZER_SUBKIND(Kind.VAR, true, true),
228
229        /**
230         * An expression whose value has been stored in a temporary variable. A
231         * <code>SubKind</code> of {@link Kind#VAR}.
232         * @jls 15. Primary.
233         */
234        TEMP_VAR_EXPRESSION_SUBKIND(Kind.VAR, true, true),
235
236        /**
237         * A simple variable reference expression. A <code>SubKind</code> of
238         * {@link Kind#EXPRESSION}.
239         * @jls 15.11. Field Access as 3.8. Identifier.
240         */
241        VAR_VALUE_SUBKIND(Kind.EXPRESSION, true, true),
242
243        /**
244         * An assignment expression. A <code>SubKind</code> of
245         * {@link Kind#EXPRESSION}.
246         * @jls 15.26. Assignment.
247         */
248        ASSIGNMENT_SUBKIND(Kind.EXPRESSION, true, true),
249
250        /**
251         * An expression which has not been wrapped in a temporary variable
252         * (reserved). A <code>SubKind</code> of {@link Kind#EXPRESSION}.
253         */
254        OTHER_EXPRESSION_SUBKIND(Kind.EXPRESSION, true, true),
255
256        /**
257         * A statement. The only <code>SubKind</code> for {@link Kind#STATEMENT}.
258         * @jls 14.5. Statement.
259         */
260        STATEMENT_SUBKIND(Kind.STATEMENT, true, false),
261
262        /**
263         * An unknown snippet. The only <code>SubKind</code> for
264         * {@link Kind#ERRONEOUS}.
265         */
266        UNKNOWN_SUBKIND(Kind.ERRONEOUS, false, false);
267
268        private final boolean isExecutable;
269        private final boolean hasValue;
270        private final Kind kind;
271
272        SubKind(Kind kind) {
273            this.kind = kind;
274            this.isExecutable = false;
275            this.hasValue = false;
276        }
277
278        SubKind(Kind kind, boolean isExecutable, boolean hasValue) {
279            this.kind = kind;
280            this.isExecutable = isExecutable;
281            this.hasValue = hasValue;
282        }
283
284        /**
285         * Is this <code>SubKind</code> executable?
286         *
287         * @return true if this <code>SubKind</code> can be executed.
288         */
289        public boolean isExecutable() {
290            return isExecutable;
291        }
292
293        /**
294         * Is this <code>SubKind</code> executable and is non-<code>void</code>.
295         *
296         * @return true if this <code>SubKind</code> has a value.
297         */
298        public boolean hasValue() {
299            return hasValue;
300        }
301
302        /**
303         * The {@link Snippet.Kind} that corresponds to this <code>SubKind</code>.
304         *
305         * @return the fixed <code>Kind</code> for this <code>SubKind</code>
306         */
307        public Kind kind() {
308            return kind;
309        }
310    }
311
312    /**
313     * Describes the current state of a Snippet.
314     * This is a dynamic property of a Snippet within the JShell state --
315     * thus is retrieved with a {@linkplain
316     * jdk.jshell.JShell#status(jdk.jshell.Snippet) query on <code>JShell</code>}.
317     * <p>
318     * The <code>Status</code> changes as the state changes.
319     * For example, creation of another snippet with
320     * {@link jdk.jshell.JShell#eval(java.lang.String) eval}
321     * may resolve dependencies of this Snippet (or invalidate those dependencies), or
322     * {@linkplain jdk.jshell.Snippet.Status#OVERWRITTEN overwrite}
323     * this Snippet changing its
324     * <code>Status</code>.
325     * <p>
326     * Important properties associated with <code>Status</code> are:
327     * {@link jdk.jshell.Snippet.Status#isDefined}, if it is visible to other
328     * existing and new snippets; and
329     * {@link jdk.jshell.Snippet.Status#isActive}, if, as the
330     * JShell state changes, the snippet will update, possibly
331     * changing <code>Status</code>.
332     * An executable Snippet can only be executed if it is in the the
333     * {@link jdk.jshell.Snippet.Status#VALID} <code>Status</code>.
334     * @see JShell#status(jdk.jshell.Snippet)
335     */
336    public enum Status {
337        /**
338         * The snippet is a valid snippet
339         * (in the context of current <code>JShell</code> state).
340         * Only snippets with <code>VALID</code>
341         * <code>Status</code> can be executed (though not all
342         * <code>VALID</code> snippets have executable code).
343         * If the snippet is a declaration or import, it is visible to other
344         * snippets ({@link Status#isDefined isDefined} <code> == true</code>).
345         * <p>
346         * The snippet will update as dependents change
347         * ({@link Status#isActive isActive} <code> == true</code>), its
348         * status could become <code>RECOVERABLE_DEFINED</code>, <code>RECOVERABLE_NOT_DEFINED</code>,
349         * <code>DROPPED</code>, or <code>OVERWRITTEN</code>.
350         */
351        VALID(true, true),
352
353        /**
354         * The snippet is a declaration snippet with potentially recoverable
355         * unresolved references or other issues in its body
356         * (in the context of current <code>JShell</code> state).
357         * Only a {@link jdk.jshell.DeclarationSnippet} can have this
358         * <code>Status</code>.
359         * The snippet has a valid signature and it is visible to other
360         * snippets ({@link Status#isDefined isDefined} <code> == true</code>)
361         * and thus can be referenced in existing or new snippets
362         * but the snippet cannot be executed.
363         * An {@link UnresolvedReferenceException} will be thrown on an attempt
364         * to execute it.
365         * <p>
366         * The snippet will update as dependents change
367         * ({@link Status#isActive isActive} <code> == true</code>), its
368         * status could become <code>VALID</code>, <code>RECOVERABLE_NOT_DEFINED</code>,
369         * <code>DROPPED</code>, or <code>OVERWRITTEN</code>.
370         * <p>
371         * Note: both <code>RECOVERABLE_DEFINED</code> and <code>RECOVERABLE_NOT_DEFINED</code>
372         * indicate potentially recoverable errors, they differ in that, for
373         * <code>RECOVERABLE_DEFINED</code>, the snippet is
374         * {@linkplain Status#isDefined defined}.
375         */
376        RECOVERABLE_DEFINED(true, true),
377
378        /**
379         * The snippet is a declaration snippet with potentially recoverable
380         * unresolved references or other issues
381         * (in the context of current <code>JShell</code> state).
382         * Only a {@link jdk.jshell.DeclarationSnippet} can have this
383         * <code>Status</code>.
384         * The snippet has an invalid signature or the implementation is
385         * otherwise unable to define it.
386         * The snippet it is not visible to other snippets
387         * ({@link Status#isDefined isDefined} <code> == false</code>)
388         * and thus cannot be referenced or executed.
389         * <p>
390         * The snippet will update as dependents change
391         * ({@link Status#isActive isActive} <code> == true</code>), its
392         * status could become <code>VALID</code>, <code>RECOVERABLE_DEFINED</code>,
393         * <code>DROPPED</code>, or <code>OVERWRITTEN</code>.
394         * <p>
395         * Note: both <code>RECOVERABLE_DEFINED</code> and <code>RECOVERABLE_NOT_DEFINED</code>
396         * indicate potentially recoverable errors, they differ in that, for
397         * <code>RECOVERABLE_DEFINED</code>, the snippet is
398         * {@linkplain Status#isDefined defined}.
399         */
400        RECOVERABLE_NOT_DEFINED(true, false),
401
402        /**
403         * The snippet is inactive because of an explicit call to
404         * the {@link JShell#drop(jdk.jshell.PersistentSnippet)}.
405         * Only a {@link jdk.jshell.PersistentSnippet} can have this
406         * <code>Status</code>.
407         * The snippet is not visible to other snippets
408         * ({@link Status#isDefined isDefined} <code> == false</code>)
409         * and thus cannot be referenced or executed.
410         * <p>
411         * The snippet will not update as dependents change
412         * ({@link Status#isActive isActive} <code> == false</code>), its
413         * <code>Status</code> will never change again.
414         */
415        DROPPED(false, false),
416
417        /**
418         * The snippet is inactive because it has been replaced by a new
419         * snippet.  This occurs when the new snippet added with
420         * {@link jdk.jshell.JShell#eval} matches a previous snippet.
421         * A <code>TypeDeclSnippet</code> will match another
422         * <code>TypeDeclSnippet</code> if the names match.
423         * For example <code>class X { }</code> will overwrite
424         * <code>class X { int ii; }</code> or
425         * <code>interface X { }</code>.
426         * A <code>MethodSnippet</code> will match another
427         * <code>MethodSnippet</code> if the names and parameter types
428         * match.
429         * For example <code>void m(int a) { }</code> will overwrite
430         * <code>int m(int a) { return a+a; }</code>.
431         * A <code>VarSnippet</code> will match another
432         * <code>VarSnippet</code> if the names match.
433         * For example <code>double z;</code> will overwrite
434         * <code>long z = 2L;</code>.
435         * Only a {@link jdk.jshell.PersistentSnippet} can have this
436         * <code>Status</code>.
437         * The snippet is not visible to other snippets
438         * ({@link Status#isDefined isDefined} <code> == false</code>)
439         * and thus cannot be referenced or executed.
440         * <p>
441         * The snippet will not update as dependents change
442         * ({@link Status#isActive isActive} <code> == false</code>), its
443         * <code>Status</code> will never change again.
444         */
445        OVERWRITTEN(false, false),
446
447        /**
448         * The snippet is inactive because it failed compilation on initial
449         * evaluation and it is not capable of becoming valid with further
450         * changes to the JShell state.
451         * The snippet is not visible to other snippets
452         * ({@link Status#isDefined isDefined} <code> == false</code>)
453         * and thus cannot be referenced or executed.
454         * <p>
455         * The snippet will not update as dependents change
456         * ({@link Status#isActive isActive} <code> == false</code>), its
457         * <code>Status</code> will never change again.
458         */
459        REJECTED(false, false),
460
461        /**
462         * The snippet is inactive because it does not yet exist.
463         * Used only in {@link SnippetEvent#previousStatus} for new
464         * snippets.
465         * {@link jdk.jshell.JShell#status(jdk.jshell.Snippet) JShell.status(Snippet)}
466         * will never return this <code>Status</code>.
467         * Vacuously, {@link Status#isDefined isDefined} and
468         * {@link Status#isActive isActive} are both defined <code>false</code>.
469         */
470        NONEXISTENT(false, false);
471
472        /**
473         * Is the Snippet active, that is, will the snippet
474         * be re-evaluated when a new
475         * {@link JShell#eval(java.lang.String) JShell.eval(String)} or
476         * {@link JShell#drop(jdk.jshell.PersistentSnippet)
477         * JShell.drop(PersistentSnippet)} that could change
478         * its status is invoked?  This is more broad than
479         * {@link Status#isDefined} since a Snippet which is
480         * {@link Status#RECOVERABLE_NOT_DEFINED}
481         * will be updated.
482         */
483        public final boolean isActive;
484
485        /**
486         * Is the snippet currently part of the defined state of the JShell?
487         * Is it visible to compilation of other snippets?
488         */
489        public final boolean isDefined;
490
491        Status(boolean isActive, boolean isDefined) {
492            this.isActive = isActive;
493            this.isDefined = isDefined;
494        }
495    }
496
497    private final Key key;
498    private final String source;
499    private final Wrap guts;
500    final String unitName;
501    private final SubKind subkind;
502
503    private int seq;
504    private String id;
505    private OuterWrap outer;
506    private Status status;
507    private List<String> unresolved;
508    private DiagList diagnostics;
509
510    Snippet(Key key, String userSource, Wrap guts, String unitName, SubKind subkind) {
511        this.key = key;
512        this.source = userSource;
513        this.guts = guts;
514        this.unitName = unitName;
515        this.subkind = subkind;
516        this.status = Status.NONEXISTENT;
517        setSequenceNumber(0);
518    }
519
520    /**** public access ****/
521
522    /**
523     * The unique identifier for the snippet. No two active snippets will have
524     * the same id().  Value of id has no prescribed meaning.  The details of
525     * how the id is generated and the mechanism to change it is documented in
526     * {@link JShell.Builder#idGenerator(BiFunction)}.
527     * @return the snippet id string.
528     */
529    public String id() {
530        return id;
531    }
532
533    /**
534     * The {@link jdk.jshell.Snippet.Kind} for the snippet.
535     * Indicates the subclass of Snippet.
536     * @return the Kind of the snippet
537     * @see Snippet.Kind
538     */
539    public Kind kind() {
540        return subkind.kind();
541    }
542
543    /**
544     * Return the {@link SubKind} of snippet.
545     * The SubKind is useful for feedback to users.
546     * @return the SubKind corresponding to this snippet
547     */
548    public SubKind subKind() {
549        return subkind;
550    }
551
552    /**
553     * Return the source code of the snippet.
554     * @return the source code corresponding to this snippet
555     */
556    public String source() {
557        return source;
558    }
559
560    @Override
561    public String toString() {
562        StringBuilder sb = new StringBuilder();
563        sb.append("Snippet:");
564        if (key() != null) {
565            sb.append(key().toString());
566        }
567        sb.append('-');
568        sb.append(source);
569        return sb.toString();
570    }
571
572    //**** internal access ****
573
574    String name() {
575        return unitName;
576    }
577
578    Key key() {
579        return key;
580    }
581
582    List<String> unresolved() {
583        return Collections.unmodifiableList(unresolved);
584    }
585
586    DiagList diagnostics() {
587        return diagnostics;
588    }
589
590    /**
591     * @return the corralled guts
592     */
593    Wrap corralled() {
594        return null;
595    }
596
597    Collection<String> declareReferences() {
598        return null;
599    }
600
601    Collection<String> bodyReferences() {
602        return null;
603    }
604
605    String importLine(JShell state) {
606        return "";
607    }
608
609    void setId(String id) {
610        this.id = id;
611    }
612
613    final void setSequenceNumber(int seq) {
614        this.seq = seq;
615    }
616
617    void setOuterWrap(OuterWrap outer) {
618        this.outer = outer;
619    }
620
621    void setCompilationStatus(Status status, List<String> unresolved, DiagList diagnostics) {
622        this.status = status;
623        this.unresolved = unresolved;
624        this.diagnostics = diagnostics;
625    }
626
627    void setDiagnostics(DiagList diagnostics) {
628        this.diagnostics = diagnostics;
629    }
630
631    void setFailed(DiagList diagnostics) {
632        this.seq = -1;
633        this.outer = null;
634        this.status = Status.REJECTED;
635        this.unresolved = Collections.emptyList();
636        this.diagnostics = diagnostics;
637    }
638
639    void setDropped() {
640        this.status = Status.DROPPED;
641    }
642
643    void setOverwritten() {
644        this.status = Status.OVERWRITTEN;
645    }
646
647    Status status() {
648        return status;
649    }
650
651    String className() {
652        return outer.className();
653    }
654
655    String classFullName() {
656        return outer.classFullName();
657    }
658
659    /**
660     * Top-level wrap
661     * @return
662     */
663    OuterWrap outerWrap() {
664        return outer;
665    }
666
667    /**
668     * Basically, class version for this Key.
669     * @return int
670     */
671    int sequenceNumber() {
672        return seq;
673    }
674
675    Wrap guts() {
676        return guts;
677    }
678
679    boolean isExecutable() {
680        return subkind.isExecutable();
681    }
682
683}
684