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.nashorn.tools.jjs; 27 28 import java.io.PrintWriter; 29 import java.util.ArrayList; 30 import java.util.List; 31 import java.util.regex.Pattern; 32 import jdk.internal.jline.console.completer.Completer; 33 import jdk.internal.jline.console.UserInterruptException; 34 import jdk.nashorn.api.tree.AssignmentTree; 35 import jdk.nashorn.api.tree.BinaryTree; 36 import jdk.nashorn.api.tree.CompilationUnitTree; 37 import jdk.nashorn.api.tree.CompoundAssignmentTree; 38 import jdk.nashorn.api.tree.ConditionalExpressionTree; 39 import jdk.nashorn.api.tree.ExpressionTree; 40 import jdk.nashorn.api.tree.ExpressionStatementTree; 41 import jdk.nashorn.api.tree.FunctionCallTree; 42 import jdk.nashorn.api.tree.IdentifierTree; 43 import jdk.nashorn.api.tree.InstanceOfTree; 44 import jdk.nashorn.api.tree.MemberSelectTree; 45 import jdk.nashorn.api.tree.NewTree; 46 import jdk.nashorn.api.tree.SimpleTreeVisitorES5_1; 47 import jdk.nashorn.api.tree.Tree; 48 import jdk.nashorn.api.tree.UnaryTree; 49 import jdk.nashorn.api.tree.Parser; 50 import jdk.nashorn.api.scripting.NashornException; 51 import jdk.nashorn.tools.PartialParser; 52 import jdk.nashorn.internal.objects.NativeSyntaxError; 53 import jdk.nashorn.internal.objects.Global; 54 import jdk.nashorn.internal.runtime.ECMAException; 55 import jdk.nashorn.internal.runtime.Context; 56 import jdk.nashorn.internal.runtime.ScriptEnvironment; 57 import jdk.nashorn.internal.runtime.ScriptRuntime; 58 59 /** 60 * A simple source completer for nashorn. Handles code completion for 61 * expressions as well as handles incomplete single line code. 62 */ 63 final class NashornCompleter implements Completer { 64 private final Context context; 65 private final Global global; 66 private final ScriptEnvironment env; 67 private final PartialParser partialParser; 68 private final PropertiesHelper propsHelper; 69 private final Parser parser; 70 71 NashornCompleter(final Context context, final Global global, 72 final PartialParser partialParser, final PropertiesHelper propsHelper) { 73 this.context = context; 74 this.global = global; 75 this.env = context.getEnv(); 76 this.partialParser = partialParser; 77 this.propsHelper = propsHelper; 78 this.parser = createParser(env); 79 } 80 81 82 /** 83 * Is this a ECMAScript SyntaxError thrown for parse issue at the given line and column? 84 * 85 * @param exp Throwable to check 86 * @param line line number to check 87 * @param column column number to check 88 * 89 * @return true if the given Throwable is a ECMAScript SyntaxError at given line, column 165 continue; 166 } else { 167 // print anything else and bail out! 168 err.println(pexp); 169 if (env._dump_on_error) { 170 pexp.printStackTrace(err); 171 } 172 return null; 173 } 174 } 175 176 // We have complete parseable code! 177 return buf.toString(); 178 } 179 } 180 181 // Pattern to match a unfinished member selection expression. object part and "." 182 // but property name missing pattern. 183 private static final Pattern SELECT_PROP_MISSING = Pattern.compile(".*\\.\\s*"); 184 185 @Override 186 public int complete(final String test, final int cursor, final List<CharSequence> result) { 187 // check that cursor is at the end of test string. Do not complete in the middle! 188 if (cursor != test.length()) { 189 return cursor; 190 } 191 192 // get the start of the last expression embedded in the given code 193 // using the partial parsing support - so that we can complete expressions 194 // inside statements, function call argument lists, array index etc. 195 final int exprStart = partialParser.getLastExpressionStart(context, test); 196 if (exprStart == -1) { 197 return cursor; 198 } 199 200 201 // extract the last expression string 202 final String exprStr = test.substring(exprStart); 203 204 // do we have an incomplete member selection expression that misses property name? 205 final boolean endsWithDot = SELECT_PROP_MISSING.matcher(exprStr).matches(); 206 207 // If this is an incomplete member selection, then it is not legal code. 208 // Make it legal by adding a random property name "x" to it. 209 final String completeExpr = endsWithDot? exprStr + "x" : exprStr; 210 211 final ExpressionTree topExpr = getTopLevelExpression(parser, completeExpr); 212 if (topExpr == null) { 213 // did not parse to be a top level expression, no suggestions! 214 return cursor; 215 } 216 217 218 // Find 'right most' expression of the top level expression 219 final Tree rightMostExpr = getRightMostExpression(topExpr); 220 if (rightMostExpr instanceof MemberSelectTree) { 221 return completeMemberSelect(exprStr, cursor, result, (MemberSelectTree)rightMostExpr, endsWithDot); 222 } else if (rightMostExpr instanceof IdentifierTree) { 223 return completeIdentifier(exprStr, cursor, result, (IdentifierTree)rightMostExpr); 224 } else { 225 // expression that we cannot handle for completion 226 return cursor; 227 } 228 } 229 230 // Internals only below this point 231 232 // fill properties of the incomplete member expression | 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.nashorn.tools.jjs; 27 28 import java.io.File; 29 import java.io.PrintWriter; 30 import java.util.ArrayList; 31 import java.util.List; 32 import java.util.regex.Pattern; 33 import javax.swing.JFileChooser; 34 import javax.swing.filechooser.FileNameExtensionFilter; 35 import jdk.internal.jline.console.completer.Completer; 36 import jdk.internal.jline.console.UserInterruptException; 37 import jdk.nashorn.api.tree.AssignmentTree; 38 import jdk.nashorn.api.tree.BinaryTree; 39 import jdk.nashorn.api.tree.CompilationUnitTree; 40 import jdk.nashorn.api.tree.CompoundAssignmentTree; 41 import jdk.nashorn.api.tree.ConditionalExpressionTree; 42 import jdk.nashorn.api.tree.ExpressionTree; 43 import jdk.nashorn.api.tree.ExpressionStatementTree; 44 import jdk.nashorn.api.tree.FunctionCallTree; 45 import jdk.nashorn.api.tree.IdentifierTree; 46 import jdk.nashorn.api.tree.InstanceOfTree; 47 import jdk.nashorn.api.tree.MemberSelectTree; 48 import jdk.nashorn.api.tree.NewTree; 49 import jdk.nashorn.api.tree.SimpleTreeVisitorES5_1; 50 import jdk.nashorn.api.tree.Tree; 51 import jdk.nashorn.api.tree.UnaryTree; 52 import jdk.nashorn.api.tree.Parser; 53 import jdk.nashorn.api.scripting.NashornException; 54 import jdk.nashorn.tools.PartialParser; 55 import jdk.nashorn.internal.objects.NativeSyntaxError; 56 import jdk.nashorn.internal.objects.Global; 57 import jdk.nashorn.internal.runtime.ECMAException; 58 import jdk.nashorn.internal.runtime.Context; 59 import jdk.nashorn.internal.runtime.ScriptEnvironment; 60 import jdk.nashorn.internal.runtime.ScriptRuntime; 61 62 /** 63 * A simple source completer for nashorn. Handles code completion for 64 * expressions as well as handles incomplete single line code. 65 */ 66 final class NashornCompleter implements Completer { 67 private final Context context; 68 private final Global global; 69 private final ScriptEnvironment env; 70 private final PartialParser partialParser; 71 private final PropertiesHelper propsHelper; 72 private final Parser parser; 73 private static final boolean BACKSLASH_FILE_SEPARATOR = File.separatorChar == '\\'; 74 75 NashornCompleter(final Context context, final Global global, 76 final PartialParser partialParser, final PropertiesHelper propsHelper) { 77 this.context = context; 78 this.global = global; 79 this.env = context.getEnv(); 80 this.partialParser = partialParser; 81 this.propsHelper = propsHelper; 82 this.parser = createParser(env); 83 } 84 85 86 /** 87 * Is this a ECMAScript SyntaxError thrown for parse issue at the given line and column? 88 * 89 * @param exp Throwable to check 90 * @param line line number to check 91 * @param column column number to check 92 * 93 * @return true if the given Throwable is a ECMAScript SyntaxError at given line, column 169 continue; 170 } else { 171 // print anything else and bail out! 172 err.println(pexp); 173 if (env._dump_on_error) { 174 pexp.printStackTrace(err); 175 } 176 return null; 177 } 178 } 179 180 // We have complete parseable code! 181 return buf.toString(); 182 } 183 } 184 185 // Pattern to match a unfinished member selection expression. object part and "." 186 // but property name missing pattern. 187 private static final Pattern SELECT_PROP_MISSING = Pattern.compile(".*\\.\\s*"); 188 189 // Pattern to match load call 190 private static final Pattern LOAD_CALL = Pattern.compile("\\s*load\\s*\\(\\s*"); 191 192 @Override 193 public int complete(final String test, final int cursor, final List<CharSequence> result) { 194 // check that cursor is at the end of test string. Do not complete in the middle! 195 if (cursor != test.length()) { 196 return cursor; 197 } 198 199 // get the start of the last expression embedded in the given code 200 // using the partial parsing support - so that we can complete expressions 201 // inside statements, function call argument lists, array index etc. 202 final int exprStart = partialParser.getLastExpressionStart(context, test); 203 if (exprStart == -1) { 204 return cursor; 205 } 206 207 208 // extract the last expression string 209 final String exprStr = test.substring(exprStart); 210 211 // do we have an incomplete member selection expression that misses property name? 212 final boolean endsWithDot = SELECT_PROP_MISSING.matcher(exprStr).matches(); 213 214 // If this is an incomplete member selection, then it is not legal code. 215 // Make it legal by adding a random property name "x" to it. 216 final String completeExpr = endsWithDot? exprStr + "x" : exprStr; 217 218 final ExpressionTree topExpr = getTopLevelExpression(parser, completeExpr); 219 if (topExpr == null) { 220 // special case for load call that looks like "load(" with optional whitespaces 221 if (LOAD_CALL.matcher(test).matches()) { 222 // throw a file dialog box 223 final JFileChooser chooser = new JFileChooser(); 224 chooser.setFileFilter(new FileNameExtensionFilter("JavaScript Files", "js")); 225 int retVal = chooser.showOpenDialog(null); 226 if (retVal == JFileChooser.APPROVE_OPTION) { 227 String name = chooser.getSelectedFile().getAbsolutePath(); 228 // handle '\' file separator 229 if (BACKSLASH_FILE_SEPARATOR) { 230 name = name.replace("\\", "\\\\"); 231 } 232 result.add("\"" + name + "\")"); 233 return cursor + name.length() + 3; 234 } 235 } 236 237 // did not parse to be a top level expression, no suggestions! 238 return cursor; 239 } 240 241 242 // Find 'right most' expression of the top level expression 243 final Tree rightMostExpr = getRightMostExpression(topExpr); 244 if (rightMostExpr instanceof MemberSelectTree) { 245 return completeMemberSelect(exprStr, cursor, result, (MemberSelectTree)rightMostExpr, endsWithDot); 246 } else if (rightMostExpr instanceof IdentifierTree) { 247 return completeIdentifier(exprStr, cursor, result, (IdentifierTree)rightMostExpr); 248 } else { 249 // expression that we cannot handle for completion 250 return cursor; 251 } 252 } 253 254 // Internals only below this point 255 256 // fill properties of the incomplete member expression |