From 970861eb877318c0da2ee27bbba25478d8b88fb2 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Tue, 31 Dec 2024 14:15:11 +0100 Subject: [PATCH] Java: support top-level var statements in JShell (IDEA-189527) GitOrigin-RevId: 7fbf56eff079ad71c5d89d7b1b7f905abc2dba74 --- .../java/parser/BasicDeclarationParser.java | 10 ++++---- .../lang/java/parser/DeclarationParser.java | 6 ++++- .../lang/java/parser/JShellParser.java | 11 ++++----- .../parser-full/jshell/VarStatement.snippet | 1 + .../psi/parser-full/jshell/VarStatement.txt | 17 ++++++++++++++ .../java/parser/jshell/JShellParsingTest.java | 23 +++++++++++-------- 6 files changed, 48 insertions(+), 20 deletions(-) create mode 100644 java/java-tests/testData/psi/parser-full/jshell/VarStatement.snippet create mode 100644 java/java-tests/testData/psi/parser-full/jshell/VarStatement.txt diff --git a/java/java-frontback-psi-impl/src/com/intellij/lang/java/parser/BasicDeclarationParser.java b/java/java-frontback-psi-impl/src/com/intellij/lang/java/parser/BasicDeclarationParser.java index b1df6e93ff13..424cffcbd4b9 100644 --- a/java/java-frontback-psi-impl/src/com/intellij/lang/java/parser/BasicDeclarationParser.java +++ b/java/java-frontback-psi-impl/src/com/intellij/lang/java/parser/BasicDeclarationParser.java @@ -29,7 +29,7 @@ import static com.intellij.psi.impl.source.BasicElementTypes.*; @ApiStatus.Experimental public class BasicDeclarationParser { public enum BaseContext { - FILE, CLASS, CODE_BLOCK, ANNOTATION_INTERFACE + FILE, CLASS, CODE_BLOCK, ANNOTATION_INTERFACE, JSHELL } private static final TokenSet BEFORE_LBRACE_ELEMENTS_SET = TokenSet.create( @@ -326,7 +326,7 @@ public class BasicDeclarationParser { PsiBuilder.Marker pos = builder.mark(); int flags = BasicReferenceParser.EAT_LAST_DOT | BasicReferenceParser.WILDCARD; - if (context == BaseContext.CODE_BLOCK) flags |= BasicReferenceParser.VAR_TYPE; + if (context == BaseContext.CODE_BLOCK || context == BaseContext.JSHELL) flags |= BasicReferenceParser.VAR_TYPE; type = myParser.getReferenceParser().parseTypeInfo(builder, flags); if (type == null) { @@ -399,7 +399,8 @@ public class BasicDeclarationParser { } if (builder.getTokenType() == JavaTokenType.LPARENTH) { - if (context == BaseContext.CLASS || context == BaseContext.ANNOTATION_INTERFACE || context == BaseContext.FILE) { // method + if (context == BaseContext.CLASS || context == BaseContext.ANNOTATION_INTERFACE || context == BaseContext.FILE + || context == BaseContext.JSHELL) { // method if (typeParams == null) { emptyElement(type.marker, myJavaElementTypeContainer.TYPE_PARAMETER_LIST); } @@ -791,7 +792,8 @@ public class BasicDeclarationParser { int declarationStart, BaseContext context) { final IElementType varType; - if (context == BaseContext.CLASS || context == BaseContext.ANNOTATION_INTERFACE || context == BaseContext.FILE) { + if (context == BaseContext.CLASS || context == BaseContext.ANNOTATION_INTERFACE || context == BaseContext.FILE + || context == BaseContext.JSHELL) { varType = myJavaElementTypeContainer.FIELD; } else if (context == BaseContext.CODE_BLOCK) { diff --git a/java/java-psi-impl/src/com/intellij/lang/java/parser/DeclarationParser.java b/java/java-psi-impl/src/com/intellij/lang/java/parser/DeclarationParser.java index b075faa63b09..eeeeb7cd2994 100644 --- a/java/java-psi-impl/src/com/intellij/lang/java/parser/DeclarationParser.java +++ b/java/java-psi-impl/src/com/intellij/lang/java/parser/DeclarationParser.java @@ -7,7 +7,7 @@ import org.jetbrains.annotations.Nullable; public class DeclarationParser extends BasicDeclarationParser { public enum Context { - FILE, CLASS, CODE_BLOCK, ANNOTATION_INTERFACE + FILE, CLASS, CODE_BLOCK, ANNOTATION_INTERFACE, JSHELL } public DeclarationParser(final @NotNull JavaParser javaParser) { @@ -30,6 +30,8 @@ public class DeclarationParser extends BasicDeclarationParser { return Context.CODE_BLOCK; case ANNOTATION_INTERFACE: return Context.ANNOTATION_INTERFACE; + case JSHELL: + return Context.JSHELL; default: throw new UnsupportedOperationException(); } @@ -49,6 +51,8 @@ public class DeclarationParser extends BasicDeclarationParser { return BaseContext.CODE_BLOCK; case ANNOTATION_INTERFACE: return BaseContext.ANNOTATION_INTERFACE; + case JSHELL: + return BaseContext.JSHELL; default: throw new UnsupportedOperationException(); } diff --git a/java/java-psi-impl/src/com/intellij/lang/java/parser/JShellParser.java b/java/java-psi-impl/src/com/intellij/lang/java/parser/JShellParser.java index d49fb1036730..325f5b1cff17 100644 --- a/java/java-psi-impl/src/com/intellij/lang/java/parser/JShellParser.java +++ b/java/java-psi-impl/src/com/intellij/lang/java/parser/JShellParser.java @@ -22,13 +22,12 @@ import java.util.function.Predicate; public class JShellParser extends JavaParser { public static final JShellParser INSTANCE = new JShellParser(); - private static final TokenSet TOP_LEVEL_DECLARATIONS = TokenSet.create( - JavaElementType.FIELD, JavaElementType.METHOD, JavaElementType.CLASS - ); + private static final TokenSet TOP_LEVEL_DECLARATIONS = + TokenSet.create(JavaElementType.FIELD, JavaElementType.METHOD, JavaElementType.CLASS); private static final Predicate IMPORT_PARSED_CONDITION = tokenType -> JavaElementType.IMPORT_STATEMENT.equals(tokenType); private static final Predicate EXPRESSION_PARSED_CONDITION = type -> type != JavaElementType.REFERENCE_EXPRESSION; - private static final Predicate STATEMENTS_PARSED_CONDITION = tokenType-> !JavaElementType.DECLARATION_STATEMENT.equals(tokenType) && - !JavaElementType.EXPRESSION_STATEMENT.equals(tokenType); + private static final Predicate STATEMENTS_PARSED_CONDITION = + tokenType -> !JavaElementType.DECLARATION_STATEMENT.equals(tokenType) && !JavaElementType.EXPRESSION_STATEMENT.equals(tokenType); private static final Predicate DECLARATION_PARSED_CONDITION = tokenType -> TOP_LEVEL_DECLARATIONS.contains(tokenType); private final FileParser myJShellFileParser = new FileParser(this) { @@ -74,7 +73,7 @@ public class JShellParser extends JavaParser { } else { revert(marker); - marker = getDeclarationParser().parse(builder, DeclarationParser.Context.CLASS); + marker = getDeclarationParser().parse(builder, DeclarationParser.Context.JSHELL); if (isParsed(marker, builder, DECLARATION_PARSED_CONDITION)) { wrapper.drop(); // don't need wrapper for top-level declaration wrapper = null; diff --git a/java/java-tests/testData/psi/parser-full/jshell/VarStatement.snippet b/java/java-tests/testData/psi/parser-full/jshell/VarStatement.snippet new file mode 100644 index 000000000000..c58eb73b0b9f --- /dev/null +++ b/java/java-tests/testData/psi/parser-full/jshell/VarStatement.snippet @@ -0,0 +1 @@ +var i = 10; \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-full/jshell/VarStatement.txt b/java/java-tests/testData/psi/parser-full/jshell/VarStatement.txt new file mode 100644 index 000000000000..cdffe534838b --- /dev/null +++ b/java/java-tests/testData/psi/parser-full/jshell/VarStatement.txt @@ -0,0 +1,17 @@ +JSHELL_FILE + PsiImportList + + PsiJShellRootClassImpl(JSHELL_ROOT_CLASS) + PsiField:i + PsiModifierList: + + PsiTypeElement:var + PsiKeyword:var('var') + PsiWhiteSpace(' ') + PsiIdentifier:i('i') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLiteralExpression:10 + PsiJavaToken:INTEGER_LITERAL('10') + PsiJavaToken:SEMICOLON(';') \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/parser/jshell/JShellParsingTest.java b/java/java-tests/testSrc/com/intellij/java/parser/jshell/JShellParsingTest.java index ca01cdeb765c..5d6a24861f3c 100644 --- a/java/java-tests/testSrc/com/intellij/java/parser/jshell/JShellParsingTest.java +++ b/java/java-tests/testSrc/com/intellij/java/parser/jshell/JShellParsingTest.java @@ -1,4 +1,4 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.java.parser.jshell; import com.intellij.ide.highlighter.JShellFileType; @@ -12,12 +12,17 @@ public class JShellParsingTest extends JavaParsingTestCase { super("parser-full/jshell", JShellFileType.DEFAULT_EXTENSION, new JShellParserDefinition(), new JavaParserDefinition()); } - public void testClass0() { doTest(true); } - public void testStatement0() { doTest(true); } - public void testStatement1() { doTest(true); } - public void testExpression0() { doTest(true); } - public void testExpression1() { doTest(true); } - public void testField0() { doTest(true); } - public void testMethod0() { doTest(true); } - public void testImport0() { doTest(true); } + public void testClass0() { doTest(); } + public void testStatement0() { doTest(); } + public void testStatement1() { doTest(); } + public void testExpression0() { doTest(); } + public void testExpression1() { doTest(); } + public void testField0() { doTest(); } + public void testMethod0() { doTest(); } + public void testImport0() { doTest(); } + public void testVarStatement() { doTest(); } + + private void doTest() { + doTest(true, true); + } }