# HG changeset patch # User rfield # Date 1486400402 28800 # Node ID cc7a4eb79b295e0e4c60446ed8c340e01b9f1c53 # Parent 19e14d35add050c121e6d2ed350b90de71faefb7 8173848: JShell: less-than causes: reached end of file while parsing Reviewed-by: jlahoda diff -r 19e14d35add0 -r cc7a4eb79b29 langtools/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.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() diff -r 19e14d35add0 -r cc7a4eb79b29 langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java --- 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 units = pt.units(); if (units.isEmpty()) { return compileFailResult(pt, userSource, Kind.ERRONEOUS); diff -r 19e14d35add0 -r cc7a4eb79b29 langtools/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java --- 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 diff -r 19e14d35add0 -r cc7a4eb79b29 langtools/src/jdk.jshell/share/classes/jdk/jshell/ReplParserFactory.java --- 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) + (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 diff -r 19e14d35add0 -r cc7a4eb79b29 langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java --- 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 units = pt.units(); if (units.isEmpty()) { return Tree.Kind.BLOCK; diff -r 19e14d35add0 -r cc7a4eb79b29 langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java --- 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 { JavaFileObject sourceToFileObject(MemoryFileManager fm, T t); @@ -179,11 +197,11 @@ private final Iterable cuts; private final List 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 -> { diff -r 19e14d35add0 -r cc7a4eb79b29 langtools/test/jdk/jshell/SimpleRegressionTest.java --- 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)); } diff -r 19e14d35add0 -r cc7a4eb79b29 langtools/test/jdk/jshell/ToolSimpleTest.java --- 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),