1 /*
   2  * Copyright (c) 2014, 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 
  26 package jdk.jshell;
  27 
  28 import java.util.List;
  29 
  30 /**
  31  * Provides analysis utilities for source code input.
  32  * Optional functionality that provides for a richer interactive experience.
  33  * Includes completion analysis:
  34  * Is the input a complete snippet of code?
  35  * Do I need to prompt for more input?
  36  * Would adding a semicolon make it complete?
  37  * Is there more than one snippet?
  38  * etc.
  39  * Also includes completion suggestions, as might be used in tab-completion.
  40  *
  41  */
  42 public abstract class SourceCodeAnalysis {
  43 
  44     /**
  45      * Given an input string, find the first snippet of code (one statement,
  46      * definition, import, or expression) and evaluate if it is complete.
  47      * @param input the input source string
  48      * @return a CompletionInfo instance with location and completeness info
  49      */
  50     public abstract CompletionInfo analyzeCompletion(String input);
  51 
  52     /**
  53      * Compute possible follow-ups for the given input.
  54      * Uses information from the current <code>JShell</code> state, including
  55      * type information, to filter the suggestions.
  56      * @param input the user input, so far
  57      * @param cursor the current position of the cursors in the given {@code input} text
  58      * @param anchor outgoing parameter - when an option will be completed, the text between
  59      *               the anchor and cursor will be deleted and replaced with the given option
  60      * @return list of candidate continuations of the given input.
  61      */
  62     public abstract List<Suggestion> completionSuggestions(String input, int cursor, int[] anchor);
  63 
  64     /**
  65      * Compute a description/help string for the given user's input.
  66      * @param input the snippet the user wrote so far
  67      * @param cursor the current position of the cursors in the given {@code input} text
  68      * @return description/help string for the given user's input
  69      */
  70     public abstract String documentation(String input, int cursor);
  71 
  72     /**
  73      * Internal only constructor
  74      */
  75     SourceCodeAnalysis() {}
  76 
  77     /**
  78      * The result of <code>analyzeCompletion(String input)</code>.
  79      * Describes the completeness and position of the first snippet in the given input.
  80      */
  81     public static class CompletionInfo {
  82 
  83         public CompletionInfo(Completeness completeness, int unitEndPos, String source, String remaining) {
  84             this.completeness = completeness;
  85             this.unitEndPos = unitEndPos;
  86             this.source = source;
  87             this.remaining = remaining;
  88         }
  89 
  90         /**
  91          * The analyzed completeness of the input.
  92          */
  93         public final Completeness completeness;
  94 
  95         /**
  96          * The end of the first unit of source.
  97          */
  98         public final int unitEndPos;
  99 
 100         /**
 101          * Source code for the first unit of code input.  For example, first
 102          * statement, or first method declaration.  Trailing semicolons will
 103          * be added, as needed
 104          */
 105         public final String source;
 106 
 107         /**
 108          * Input remaining after the source
 109          */
 110         public final String remaining;
 111     }
 112 
 113     /**
 114      * Describes the completeness of the given input.
 115      */
 116     public enum Completeness {
 117         /**
 118          * The input is a complete source snippet (declaration or statement) as is.
 119          */
 120         COMPLETE(true),
 121 
 122         /**
 123          * With this addition of a semicolon the input is a complete source snippet.
 124          * This will only be returned when the end of input is encountered.
 125          */
 126         COMPLETE_WITH_SEMI(true),
 127 
 128         /**
 129          * There must be further source beyond the given input in order for it
 130          * to be complete.  A semicolon would not complete it.
 131          * This will only be returned when the end of input is encountered.
 132          */
 133         DEFINITELY_INCOMPLETE(false),
 134 
 135         /**
 136          * A statement with a trailing (non-terminated) empty statement.
 137          * Though technically it would be a complete statement
 138          * with the addition of a semicolon, it is rare
 139          * that that assumption is the desired behavior.
 140          * The input is considered incomplete.  Comments and white-space are
 141          * still considered empty.
 142          */
 143         CONSIDERED_INCOMPLETE(false),
 144 
 145 
 146         /**
 147          * An empty input.
 148          * The input is considered incomplete.  Comments and white-space are
 149          * still considered empty.
 150          */
 151         EMPTY(false),
 152 
 153         /**
 154          * The completeness of the input could not be determined because it
 155          * contains errors. Error detection is not a goal of completeness
 156          * analysis, however errors interfered with determining its completeness.
 157          * The input is considered complete because evaluating is the best
 158          * mechanism to get error information.
 159          */
 160         UNKNOWN(true);
 161 
 162         /**
 163          * Is the first snippet of source complete. For example, "x=" is not
 164          * complete, but "x=2" is complete, even though a subsequent line could
 165          * make it "x=2+2". Already erroneous code is marked complete.
 166          */
 167         public final boolean isComplete;
 168 
 169         Completeness(boolean isComplete) {
 170             this.isComplete = isComplete;
 171         }
 172     }
 173 
 174     /**
 175      * A candidate for continuation of the given user's input.
 176      */
 177     public static class Suggestion {
 178 
 179         /**
 180          * Create a {@code Suggestion} instance.
 181          * @param continuation a candidate continuation of the user's input
 182          * @param isSmart is the candidate "smart"
 183          */
 184         public Suggestion(String continuation, boolean isSmart) {
 185             this.continuation = continuation;
 186             this.isSmart = isSmart;
 187         }
 188 
 189         /**
 190          * The candidate continuation of the given user's input.
 191          */
 192         public final String continuation;
 193 
 194         /**
 195          * Is it an input continuation that matches the target type and is thus more
 196          * likely to be the desired continuation. A smart continuation
 197          * is preferred.
 198          */
 199         public final boolean isSmart;
 200     }
 201 }