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