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 /**Infer the type of the given expression. Returns null if the type of the expression cannot 78 * be inferred. 79 * 80 * @param code the expression for which the type should be inferred 81 * @param cursor current cursor position in the given code 82 * @return the inferred type, or null if it cannot be inferred 83 */ 84 public abstract String analyzeType(String code, int cursor); 85 86 /**List the possible FQNs for an identifier in the given code immediately 87 * to the right of the given cursor position. 88 * 89 * @param code the expression for which the candidate FQNs should be computed 90 * @param cursor current cursor position in the given code 91 * @return the gathered FQNs 92 */ 93 public abstract IndexResult getDeclaredSymbols(String code, int cursor); 94 95 /** 96 * The result of <code>analyzeCompletion(String input)</code>. 97 * Describes the completeness and position of the first snippet in the given input. 98 */ 99 public static class CompletionInfo { 100 101 public CompletionInfo(Completeness completeness, int unitEndPos, String source, String remaining) { 102 this.completeness = completeness; 103 this.unitEndPos = unitEndPos; 104 this.source = source; 105 this.remaining = remaining; 106 } 107 108 /** 109 * The analyzed completeness of the input. 110 */ 111 public final Completeness completeness; 112 113 /** 114 * The end of the first unit of source. 115 */ 116 public final int unitEndPos; 117 118 /** 119 * Source code for the first unit of code input. For example, first 120 * statement, or first method declaration. Trailing semicolons will 121 * be added, as needed 122 */ 123 public final String source; 124 125 /** 126 * Input remaining after the source 127 */ 128 public final String remaining; 129 } 130 131 /** 132 * Describes the completeness of the given input. 133 */ 134 public enum Completeness { 135 /** 136 * The input is a complete source snippet (declaration or statement) as is. 137 */ 138 COMPLETE(true), 139 140 /** 141 * With this addition of a semicolon the input is a complete source snippet. 142 * This will only be returned when the end of input is encountered. 143 */ 144 COMPLETE_WITH_SEMI(true), 145 146 /** 147 * There must be further source beyond the given input in order for it 148 * to be complete. A semicolon would not complete it. 149 * This will only be returned when the end of input is encountered. 150 */ 151 DEFINITELY_INCOMPLETE(false), 152 153 /** 154 * A statement with a trailing (non-terminated) empty statement. 155 * Though technically it would be a complete statement 156 * with the addition of a semicolon, it is rare 157 * that that assumption is the desired behavior. 158 * The input is considered incomplete. Comments and white-space are 159 * still considered empty. 160 */ 161 CONSIDERED_INCOMPLETE(false), 162 163 164 /** 165 * An empty input. 166 * The input is considered incomplete. Comments and white-space are 167 * still considered empty. 168 */ 169 EMPTY(false), 170 171 /** 172 * The completeness of the input could not be determined because it 173 * contains errors. Error detection is not a goal of completeness 174 * analysis, however errors interfered with determining its completeness. 175 * The input is considered complete because evaluating is the best 176 * mechanism to get error information. 177 */ 178 UNKNOWN(true); 179 180 /** 181 * Is the first snippet of source complete. For example, "x=" is not 182 * complete, but "x=2" is complete, even though a subsequent line could 183 * make it "x=2+2". Already erroneous code is marked complete. 184 */ 185 public final boolean isComplete; 186 187 Completeness(boolean isComplete) { 188 this.isComplete = isComplete; 189 } 190 } 191 192 /** 193 * A candidate for continuation of the given user's input. 194 */ 195 public static class Suggestion { 196 197 /** 198 * Create a {@code Suggestion} instance. 199 * @param continuation a candidate continuation of the user's input 200 * @param isSmart is the candidate "smart" 201 */ 202 public Suggestion(String continuation, boolean isSmart) { 203 this.continuation = continuation; 204 this.isSmart = isSmart; 205 } 206 207 /** 208 * The candidate continuation of the given user's input. 209 */ 210 public final String continuation; 211 212 /** 213 * Is it an input continuation that matches the target type and is thus more 214 * likely to be the desired continuation. A smart continuation 215 * is preferred. 216 */ 217 public final boolean isSmart; 218 } 219 220 /**List of possible qualified names. 221 */ 222 public static final class IndexResult { 223 224 private final List<String> fqns; 225 private final int simpleNameLength; 226 private final boolean upToDate; 227 private final boolean resolvable; 228 229 public IndexResult(List<String> fqns, int simpleNameLength, boolean upToDate, boolean resolvable) { 230 this.fqns = fqns; 231 this.simpleNameLength = simpleNameLength; 232 this.upToDate = upToDate; 233 this.resolvable = resolvable; 234 } 235 236 /**Candidate fully qualified names (FQNs). 237 * 238 * @return possible fully qualified names 239 */ 240 public List<String> getFqns() { 241 return fqns; 242 } 243 244 /**The length of the unresolvable simple name in the original code for which the 245 * FQNs where computed. 246 * 247 * @return the length of the simple name; -1 if there is no name right left to the cursor for 248 * which the candidates could be computed 249 */ 250 public int getSimpleNameLength() { 251 return simpleNameLength; 252 } 253 254 /**Whether the result is based on up to date data. 255 * 256 * @return true iff the results is based on up-to-date data 257 */ 258 public boolean isUpToDate() { 259 return upToDate; 260 } 261 262 /**The given identifier refers to a resolvable element. 263 * 264 * @return true iff the given identifier refers to a resolvable element 265 */ 266 public boolean isResolvable() { 267 return resolvable; 268 } 269 270 } 271 }