8173848: JShell: less-than causes: reached end of file while parsing
authorrfield
Mon, 06 Feb 2017 09:00:02 -0800
changeset 43586 cc7a4eb79b29
parent 43585 19e14d35add0
child 43587 6103af590758
8173848: JShell: less-than causes: reached end of file while parsing Reviewed-by: jlahoda
langtools/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/ReplParserFactory.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java
langtools/test/jdk/jshell/SimpleRegressionTest.java
langtools/test/jdk/jshell/ToolSimpleTest.java
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java	Mon Feb 06 15:57:35 2017 +0100
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java	Mon Feb 06 09:00:02 2017 -0800
@@ -85,7 +85,7 @@
         try {
             Parser parser = new Parser(
                     () -> new Matched(scannerFactory.newScanner(s, false)),
-                    () -> proc.taskFactory.new ParseTask(s));
+                    () -> proc.taskFactory.parse(s));
             Completeness stat = parser.parseUnit();
             int endPos = stat == Completeness.UNKNOWN
                     ? s.length()
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Mon Feb 06 15:57:35 2017 +0100
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Mon Feb 06 09:00:02 2017 -0800
@@ -155,7 +155,7 @@
         if (compileSource.length() == 0) {
             return Collections.emptyList();
         }
-        ParseTask pt = state.taskFactory.new ParseTask(compileSource);
+        ParseTask pt = state.taskFactory.parse(compileSource);
         List<? extends Tree> units = pt.units();
         if (units.isEmpty()) {
             return compileFailResult(pt, userSource, Kind.ERRONEOUS);
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java	Mon Feb 06 15:57:35 2017 +0100
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java	Mon Feb 06 09:00:02 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,7 +39,6 @@
 import static com.sun.tools.javac.parser.Tokens.TokenKind.INTERFACE;
 import static com.sun.tools.javac.parser.Tokens.TokenKind.LPAREN;
 import static com.sun.tools.javac.parser.Tokens.TokenKind.MONKEYS_AT;
-import static com.sun.tools.javac.parser.Tokens.TokenKind.PACKAGE;
 import static com.sun.tools.javac.parser.Tokens.TokenKind.SEMI;
 import static com.sun.tools.javac.parser.Tokens.TokenKind.VOID;
 import com.sun.tools.javac.tree.JCTree;
@@ -48,10 +47,8 @@
 import com.sun.tools.javac.tree.JCTree.JCExpression;
 import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
 import com.sun.tools.javac.tree.JCTree.JCModifiers;
-import com.sun.tools.javac.tree.JCTree.JCPackageDecl;
 import com.sun.tools.javac.tree.JCTree.JCStatement;
 import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
-import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
 import com.sun.tools.javac.tree.JCTree.Tag;
 import static com.sun.tools.javac.tree.JCTree.Tag.IDENT;
 import com.sun.tools.javac.util.List;
@@ -68,12 +65,17 @@
  */
 class ReplParser extends JavacParser {
 
+    // force starting in expression mode
+    private final boolean forceExpression;
+
     public ReplParser(ParserFactory fac,
             com.sun.tools.javac.parser.Lexer S,
             boolean keepDocComments,
             boolean keepLineMap,
-            boolean keepEndPositions) {
+            boolean keepEndPositions,
+            boolean forceExpression) {
         super(fac, S, keepDocComments, keepLineMap, keepEndPositions);
+        this.forceExpression = forceExpression;
     }
 
     /**
@@ -205,7 +207,10 @@
                         nextToken();
                     } else {
                         // return type of method, declared type of variable, or an expression
-                        t = term(EXPR | TYPE);
+                        // unless expression is being forced
+                        t = term(forceExpression
+                                ? EXPR
+                                : EXPR | TYPE);
                     }
                     if (token.kind == COLON && t.hasTag(IDENT)) {
                         // labelled statement
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ReplParserFactory.java	Mon Feb 06 15:57:35 2017 +0100
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ReplParserFactory.java	Mon Feb 06 09:00:02 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,25 +36,26 @@
  */
 class ReplParserFactory extends ParserFactory {
 
-    public static ParserFactory instance(Context context) {
-        ParserFactory instance = context.get(parserFactoryKey);
-        if (instance == null) {
-            instance = new ReplParserFactory(context);
-        }
-        return instance;
+    // force starting in expression mode
+    private final boolean forceExpression;
+
+    public static void preRegister(Context context, boolean forceExpression) {
+        context.put(parserFactoryKey, (Context.Factory<ParserFactory>)
+                (c -> new ReplParserFactory(c, forceExpression)));
     }
 
     private final ScannerFactory scannerFactory;
 
-    protected ReplParserFactory(Context context) {
+    protected ReplParserFactory(Context context, boolean forceExpression) {
         super(context);
+        this.forceExpression = forceExpression;
         this.scannerFactory = ScannerFactory.instance(context);
     }
 
     @Override
     public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap) {
         com.sun.tools.javac.parser.Lexer lexer = scannerFactory.newScanner(input, keepDocComments);
-        return new ReplParser(this, lexer, keepDocComments, keepLineMap, keepEndPos);
+        return new ReplParser(this, lexer, keepDocComments, keepLineMap, keepEndPos, forceExpression);
     }
 
     @Override
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java	Mon Feb 06 15:57:35 2017 +0100
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java	Mon Feb 06 09:00:02 2017 -0800
@@ -227,7 +227,7 @@
     }
 
     private Tree.Kind guessKind(String code) {
-        ParseTask pt = proc.taskFactory.new ParseTask(code);
+        ParseTask pt = proc.taskFactory.parse(code);
         List<? extends Tree> units = pt.units();
         if (units.isEmpty()) {
             return Tree.Kind.BLOCK;
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java	Mon Feb 06 15:57:35 2017 +0100
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java	Mon Feb 06 09:00:02 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -61,6 +61,7 @@
 import javax.tools.FileObject;
 import jdk.jshell.MemoryFileManager.SourceMemoryJavaFileObject;
 import java.lang.Runtime.Version;
+import com.sun.source.tree.Tree.Kind;
 
 /**
  * The primary interface to the compiler API.  Parsing, analysis, and
@@ -100,6 +101,23 @@
         return fileManager;
     }
 
+    // Parse a snippet and return our parse task handler
+    ParseTask parse(final String source) {
+        ParseTask pt = state.taskFactory.new ParseTask(source, false);
+        if (!pt.units().isEmpty()
+                && pt.units().get(0).getKind() == Kind.EXPRESSION_STATEMENT
+                && pt.getDiagnostics().hasOtherThanNotStatementErrors()) {
+            // It failed, it may be an expression being incorrectly
+            // parsed as having a leading type variable, example:   a < b
+            // Try forcing interpretation as an expression
+            ParseTask ept = state.taskFactory.new ParseTask(source, true);
+            if (!ept.getDiagnostics().hasOtherThanNotStatementErrors()) {
+                return ept;
+            }
+        }
+        return pt;
+    }
+
     private interface SourceHandler<T> {
 
         JavaFileObject sourceToFileObject(MemoryFileManager fm, T t);
@@ -179,11 +197,11 @@
         private final Iterable<? extends CompilationUnitTree> cuts;
         private final List<? extends Tree> units;
 
-        ParseTask(final String source) {
+        ParseTask(final String source, final boolean forceExpression) {
             super(Stream.of(source),
                     new StringSourceHandler(),
                     "-XDallowStringFolding=false", "-proc:none");
-            ReplParserFactory.instance(getContext());
+            ReplParserFactory.preRegister(getContext(), forceExpression);
             cuts = parse();
             units = Util.stream(cuts)
                     .flatMap(cut -> {
--- a/langtools/test/jdk/jshell/SimpleRegressionTest.java	Mon Feb 06 15:57:35 2017 +0100
+++ b/langtools/test/jdk/jshell/SimpleRegressionTest.java	Mon Feb 06 09:00:02 2017 -0800
@@ -22,7 +22,7 @@
  */
 
 /*
- * @test 8130450 8158906 8154374 8166400 8171892
+ * @test 8130450 8158906 8154374 8166400 8171892 8173848
  * @summary simple regression test
  * @build KullaTesting TestingInputStream
  * @run testng SimpleRegressionTest
@@ -76,6 +76,15 @@
         assertEval("c;", "600");
     }
 
+    public void testLessThanParsing() {
+        assertEval("int x = 3;", "3");
+        assertEval("int y = 4;", "4");
+        assertEval("int z = 5;", "5");
+        assertEval("x < y", "true");
+        assertEval("x < y;", "true");
+        assertEval("x < y && y < z", "true");
+    }
+
     public void testNotStmtCannotResolve() {
         assertDeclareFail("dfasder;", new ExpectedDiagnostic("compiler.err.cant.resolve.location", 0, 7, 0, -1, -1, Diagnostic.Kind.ERROR));
     }
--- a/langtools/test/jdk/jshell/ToolSimpleTest.java	Mon Feb 06 15:57:35 2017 +0100
+++ b/langtools/test/jdk/jshell/ToolSimpleTest.java	Mon Feb 06 09:00:02 2017 -0800
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103  8165405 8173073
+ * @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103  8165405 8173073 8173848
  * @summary Simple jshell tool tests
  * @modules jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.main
@@ -74,6 +74,18 @@
     }
 
     @Test
+    public void testLessThan() {
+        test(
+                (a) -> assertCommand(a, "45", "$1 ==> 45"),
+                (a) -> assertCommand(a, "72", "$2 ==> 72"),
+                (a) -> assertCommand(a, "$1 < $2", "$3 ==> true"),
+                (a) -> assertCommand(a, "int a, b", "a ==> 0\n" +
+                        "b ==> 0"),
+                (a) -> assertCommand(a, "a < b", "$6 ==> false")
+        );
+    }
+
+    @Test
     public void oneLineOfError() {
         test(
                 (a) -> assertCommand(a, "12+", null),