mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-359853 convert JShell parser to KMP
GitOrigin-RevId: a11082e3c00bdcf766c5e2ad5a2c3f14287d774b
This commit is contained in:
committed by
intellij-monorepo-bot
parent
f89994558f
commit
31462ed80b
+14
@@ -0,0 +1,14 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.java.frontback.psi.impl.syntax
|
||||
|
||||
import com.intellij.java.syntax.JavaSyntaxDefinition
|
||||
import com.intellij.platform.syntax.SyntaxElementTypeSet
|
||||
import com.intellij.platform.syntax.lexer.Lexer
|
||||
import com.intellij.platform.syntax.psi.LanguageSyntaxDefinition
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
|
||||
internal class JShellSyntaxDefinitionExtension : LanguageSyntaxDefinition {
|
||||
override fun getLexer(): Lexer = JavaSyntaxDefinition.createLexer(LanguageLevel.HIGHEST)
|
||||
|
||||
override fun getCommentTokens(): SyntaxElementTypeSet = JavaSyntaxDefinition.commentSet
|
||||
}
|
||||
@@ -106,6 +106,7 @@
|
||||
<stubElementRegistryExtension implementation="com.intellij.psi.impl.java.stubs.JavaStubRegistryExtension"/>
|
||||
|
||||
<syntax.syntaxDefinition language="JAVA" implementationClass="com.intellij.java.frontback.psi.impl.syntax.JavaSyntaxDefinitionExtension"/>
|
||||
<syntax.syntaxDefinition language="JShellLanguage" implementationClass="com.intellij.java.frontback.psi.impl.syntax.JShellSyntaxDefinitionExtension"/>
|
||||
|
||||
<metaLanguage implementation="com.intellij.lang.jvm.JvmMetaLanguage"/>
|
||||
<java.elementFinder implementation="com.intellij.psi.impl.PsiElementFinderImpl" id="java" order="first"/>
|
||||
@@ -136,6 +137,8 @@
|
||||
<lang.parserDefinition language="JShellLanguage" implementationClass="com.intellij.lang.java.JShellParserDefinition"/>
|
||||
<lang.parserDefinition language="JAVA" implementationClass="com.intellij.lang.java.JavaParserDefinition"/>
|
||||
<syntax.elementTypeConverter language="JAVA" implementationClass="com.intellij.lang.java.syntax.JavaElementTypeConverterExtension"/>
|
||||
<syntax.elementTypeConverter language="JShellLanguage" implementationClass="com.intellij.lang.java.syntax.JavaElementTypeConverterExtension"/>
|
||||
<syntax.elementTypeConverter language="JShellLanguage" implementationClass="com.intellij.lang.java.syntax.JShellElementTypeConverterExtension"/>
|
||||
<lang.ast.factory language="JAVA" implementationClass="com.intellij.psi.impl.source.tree.JavaASTFactory"/>
|
||||
<classTypePointerFactory implementation="com.intellij.psi.impl.smartPointers.PsiClassReferenceTypePointerFactory"/>
|
||||
<lang.elementManipulator forClass="com.intellij.psi.javadoc.PsiDocTag"
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.lang.java;
|
||||
|
||||
import com.intellij.java.syntax.JavaSyntaxDefinition;
|
||||
import com.intellij.java.syntax.parser.JShellParser;
|
||||
import com.intellij.lang.*;
|
||||
import com.intellij.platform.syntax.psi.ParsingDiagnostics;
|
||||
import com.intellij.platform.syntax.psi.PsiSyntaxBuilder;
|
||||
import com.intellij.platform.syntax.psi.PsiSyntaxBuilderFactory;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.tree.IFileElementType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
class JShellFileElementType extends IFileElementType {
|
||||
JShellFileElementType() {
|
||||
super("JSHELL_FILE", JShellLanguage.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ASTNode doParseContents(@NotNull ASTNode chameleon, @NotNull PsiElement psi) {
|
||||
Language languageForParser = JShellLanguage.INSTANCE;
|
||||
LanguageLevel languageLevel = LanguageLevel.HIGHEST;
|
||||
JShellParser jShellParser = new JShellParser(languageLevel);
|
||||
PsiSyntaxBuilder builder = PsiSyntaxBuilderFactory.getInstance().createBuilder(chameleon,
|
||||
JavaSyntaxDefinition.createLexer(languageLevel),
|
||||
JShellLanguage.INSTANCE,
|
||||
chameleon.getChars());
|
||||
long startTime = System.nanoTime();
|
||||
jShellParser.parse(builder.getSyntaxTreeBuilder());
|
||||
ASTNode node = builder.getTreeBuilt();
|
||||
ParsingDiagnostics.registerParse(builder, languageForParser, System.nanoTime() - startTime);
|
||||
return node.getFirstChildNode();
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,6 @@
|
||||
package com.intellij.lang.java;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.PsiBuilder;
|
||||
import com.intellij.lang.PsiParser;
|
||||
import com.intellij.lang.java.parser.JShellParser;
|
||||
import com.intellij.lang.java.parser.JavaParserUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.FileViewProvider;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
@@ -21,18 +15,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
* @author Eugene Zhuravlev
|
||||
*/
|
||||
public final class JShellParserDefinition extends JavaParserDefinition {
|
||||
public static final IFileElementType FILE_ELEMENT_TYPE = new IFileElementType("JSHELL_FILE", JShellLanguage.INSTANCE);
|
||||
|
||||
private static final PsiParser PARSER = new PsiParser() {
|
||||
@Override
|
||||
public @NotNull ASTNode parse(@NotNull IElementType rootElement, @NotNull PsiBuilder builder) {
|
||||
JavaParserUtil.setLanguageLevel(builder, LanguageLevel.HIGHEST);
|
||||
final PsiBuilder.Marker r = builder.mark();
|
||||
JShellParser.INSTANCE.getFileParser().parse(builder);
|
||||
r.done(rootElement);
|
||||
return builder.getTreeBuilt();
|
||||
}
|
||||
};
|
||||
public static final IFileElementType FILE_ELEMENT_TYPE = new JShellFileElementType();
|
||||
|
||||
@Override
|
||||
public @NotNull PsiFile createFile(@NotNull FileViewProvider viewProvider) {
|
||||
@@ -52,9 +35,4 @@ public final class JShellParserDefinition extends JavaParserDefinition {
|
||||
}
|
||||
return super.createElement(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PsiParser createParser(Project project) {
|
||||
return PARSER;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.lang.java.parser;
|
||||
|
||||
import com.intellij.core.JavaPsiBundle;
|
||||
import com.intellij.lang.LighterASTNode;
|
||||
import com.intellij.lang.PsiBuilder;
|
||||
import com.intellij.lang.impl.PsiBuilderImpl;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.impl.source.tree.ElementType;
|
||||
import com.intellij.psi.impl.source.tree.JShellElementType;
|
||||
import com.intellij.psi.impl.source.tree.JavaElementType;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
*/
|
||||
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 Predicate<IElementType> IMPORT_PARSED_CONDITION = tokenType -> JavaElementType.IMPORT_STATEMENT == tokenType;
|
||||
private static final Predicate<IElementType> DECLARATION_PARSED_CONDITION = tokenType -> TOP_LEVEL_DECLARATIONS.contains(tokenType);
|
||||
|
||||
private final FileParser myJShellFileParser = new FileParser(this) {
|
||||
private final TokenSet IMPORT_PARSING_STOP_LIST = TokenSet.orSet(
|
||||
IMPORT_LIST_STOPPER_SET,
|
||||
TokenSet.orSet(
|
||||
ElementType.MODIFIER_BIT_SET,
|
||||
ElementType.JAVA_COMMENT_BIT_SET,
|
||||
ElementType.EXPRESSION_BIT_SET,
|
||||
ElementType.JAVA_STATEMENT_BIT_SET,
|
||||
ElementType.PRIMITIVE_TYPE_BIT_SET,
|
||||
TokenSet.create(JShellElementType.ROOT_CLASS, JavaTokenType.IDENTIFIER)
|
||||
)
|
||||
);
|
||||
|
||||
@Override
|
||||
public void parse(@NotNull PsiBuilder builder) {
|
||||
parseImportList(builder, b -> IMPORT_PARSING_STOP_LIST.contains(b.getTokenType()));
|
||||
|
||||
final PsiBuilder.Marker rootClass = builder.mark();
|
||||
try {
|
||||
while (!builder.eof()) {
|
||||
PsiBuilder.Marker wrapper = builder.mark();
|
||||
IElementType wrapperType = null;
|
||||
|
||||
PsiBuilder.Marker marker = parseImportStatement(builder);
|
||||
if (isParsed(marker, builder, IMPORT_PARSED_CONDITION)) {
|
||||
wrapperType = JShellElementType.IMPORT_HOLDER;
|
||||
}
|
||||
else {
|
||||
revert(marker);
|
||||
marker = getDeclarationParser().parse(builder, DeclarationParser.Context.JSHELL);
|
||||
if (isParsed(marker, builder, DECLARATION_PARSED_CONDITION) && !((PsiBuilderImpl)builder).hasErrorsAfter(marker)) {
|
||||
wrapper.drop(); // don't need wrapper for top-level declaration
|
||||
wrapper = null;
|
||||
}
|
||||
else {
|
||||
revert(marker);
|
||||
marker = getStatementParser().parseStatement(builder);
|
||||
if (marker != null && !((PsiBuilderImpl)builder).hasErrorsAfter(marker)) {
|
||||
wrapperType = JShellElementType.STATEMENTS_HOLDER;
|
||||
}
|
||||
else {
|
||||
revert(marker);
|
||||
marker = getExpressionParser().parse(builder);
|
||||
wrapperType = marker != null ? JShellElementType.STATEMENTS_HOLDER : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (marker == null) {
|
||||
wrapper.drop();
|
||||
break;
|
||||
}
|
||||
|
||||
if (wrapper != null) {
|
||||
wrapper.done(wrapperType);
|
||||
}
|
||||
}
|
||||
|
||||
if (!builder.eof()) {
|
||||
builder.mark().error(JavaPsiBundle.message("unexpected.token"));
|
||||
while (!builder.eof()) {
|
||||
builder.advanceLexer();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
rootClass.done(JShellElementType.ROOT_CLASS);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private static boolean isParsed(@Nullable PsiBuilder.Marker parsedMarker, PsiBuilder builder, final Predicate<? super IElementType> cond) {
|
||||
if (parsedMarker == null) {
|
||||
return false;
|
||||
}
|
||||
final LighterASTNode lastDone = builder.getLatestDoneMarker();
|
||||
if (lastDone == null) {
|
||||
return false;
|
||||
}
|
||||
return cond.test(lastDone.getTokenType());
|
||||
}
|
||||
|
||||
private static void revert(PsiBuilder.Marker parsedMarker) {
|
||||
if (parsedMarker != null) {
|
||||
parsedMarker.rollbackTo();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FileParser getFileParser() {
|
||||
return myJShellFileParser;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.lang.java.syntax
|
||||
|
||||
import com.intellij.java.syntax.element.JShellSyntaxElementType
|
||||
import com.intellij.lang.java.JShellParserDefinition
|
||||
import com.intellij.platform.syntax.psi.ElementTypeConverter
|
||||
import com.intellij.platform.syntax.psi.ElementTypeConverterFactory
|
||||
import com.intellij.platform.syntax.psi.elementTypeConverterOf
|
||||
import com.intellij.psi.impl.source.tree.JShellElementType
|
||||
|
||||
internal class JShellElementTypeConverterExtension : ElementTypeConverterFactory {
|
||||
override fun getElementTypeConverter(): ElementTypeConverter = JShellElementTypeConverter
|
||||
}
|
||||
|
||||
internal val JShellElementTypeConverter: ElementTypeConverter = elementTypeConverterOf(
|
||||
JShellSyntaxElementType.FILE to JShellParserDefinition.FILE_ELEMENT_TYPE,
|
||||
JShellSyntaxElementType.ROOT_CLASS to JShellElementType.ROOT_CLASS,
|
||||
JShellSyntaxElementType.IMPORT_HOLDER to JShellElementType.IMPORT_HOLDER,
|
||||
JShellSyntaxElementType.STATEMENTS_HOLDER to JShellElementType.STATEMENTS_HOLDER,
|
||||
)
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.java.syntax.element
|
||||
|
||||
import com.intellij.platform.syntax.SyntaxElementType
|
||||
|
||||
object JShellSyntaxElementType {
|
||||
val FILE: SyntaxElementType = SyntaxElementType("JSHELL_FILE")
|
||||
val ROOT_CLASS: SyntaxElementType = SyntaxElementType("JSHELL_ROOT_CLASS")
|
||||
val STATEMENTS_HOLDER: SyntaxElementType = SyntaxElementType("JSHELL_STATEMENTS_HOLDER")
|
||||
val IMPORT_HOLDER: SyntaxElementType = SyntaxElementType("JSHELL_IMPORT_HOLDER")
|
||||
}
|
||||
@@ -1,13 +1,11 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.java.syntax.parser
|
||||
|
||||
import com.intellij.java.syntax.JavaSyntaxBundle.message
|
||||
import com.intellij.java.syntax.JavaSyntaxBundle.resourceBundle
|
||||
import com.intellij.java.syntax.JavaSyntaxBundle
|
||||
import com.intellij.java.syntax.element.JavaSyntaxElementType
|
||||
import com.intellij.java.syntax.element.JavaSyntaxTokenType
|
||||
import com.intellij.java.syntax.element.SyntaxElementTypes
|
||||
import com.intellij.java.syntax.element.WhiteSpaceAndCommentSetHolder
|
||||
import com.intellij.openapi.util.NlsContexts
|
||||
import com.intellij.platform.syntax.SyntaxElementType
|
||||
import com.intellij.platform.syntax.SyntaxElementTypeSet
|
||||
import com.intellij.platform.syntax.i18n.ResourceBundle
|
||||
@@ -16,8 +14,12 @@ import com.intellij.platform.syntax.syntaxElementTypeSetOf
|
||||
import com.intellij.platform.syntax.util.parser.SyntaxBuilderUtil.expect
|
||||
|
||||
open class FileParser(private val myParser: JavaParser) {
|
||||
fun parse(builder: SyntaxTreeBuilder) {
|
||||
parseFile(builder, { b -> this.stopImportListParsing(b) }, resourceBundle, "expected.class.or.interface")
|
||||
open fun parse(builder: SyntaxTreeBuilder) {
|
||||
parseFile(builder = builder,
|
||||
importListStopper = { b -> this.stopImportListParsing(b) },
|
||||
bundle = JavaSyntaxBundle.resourceBundle,
|
||||
errorMessageKey = "expected.class.or.interface"
|
||||
)
|
||||
}
|
||||
|
||||
fun parseFile(
|
||||
@@ -44,7 +46,7 @@ open class FileParser(private val myParser: JavaParser) {
|
||||
if (declaration == null) declaration = parseInitial(builder)
|
||||
if (declaration != null) {
|
||||
if (invalidElements != null) {
|
||||
invalidElements.errorBefore(error(bundle, errorMessageKey), declaration)
|
||||
invalidElements.errorBefore(bundle.message(errorMessageKey), declaration)
|
||||
invalidElements = null
|
||||
}
|
||||
if (firstDeclarationOk == null) {
|
||||
@@ -66,7 +68,7 @@ open class FileParser(private val myParser: JavaParser) {
|
||||
if (firstDeclarationOk == null) firstDeclarationOk = false
|
||||
}
|
||||
|
||||
invalidElements?.error(error(bundle, errorMessageKey))
|
||||
invalidElements?.error(bundle.message(errorMessageKey))
|
||||
|
||||
if (impListInfo.second && firstDeclarationOk == true) {
|
||||
impListInfo.first.setCustomEdgeTokenBinders(myWhiteSpaceAndCommentSetHolder.getPrecedingCommentBinder(myParser.languageLevel),
|
||||
@@ -108,7 +110,7 @@ open class FileParser(private val myParser: JavaParser) {
|
||||
|
||||
val ref = myParser.referenceParser.parseJavaCodeReference(builder, true, false, false, false)
|
||||
if (ref == null) {
|
||||
statement.error(message("expected.class.or.interface"))
|
||||
statement.error(JavaSyntaxBundle.message("expected.class.or.interface"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -117,7 +119,7 @@ open class FileParser(private val myParser: JavaParser) {
|
||||
JavaParserUtil.done(statement, JavaSyntaxElementType.PACKAGE_STATEMENT, myParser.languageLevel, myWhiteSpaceAndCommentSetHolder)
|
||||
}
|
||||
|
||||
private fun parseImportList(
|
||||
protected fun parseImportList(
|
||||
builder: SyntaxTreeBuilder,
|
||||
stopper: (SyntaxTreeBuilder) -> Boolean,
|
||||
): Pair<SyntaxTreeBuilder.Marker, Boolean> {
|
||||
@@ -138,7 +140,7 @@ open class FileParser(private val myParser: JavaParser) {
|
||||
if (statement != null) {
|
||||
isEmpty = false
|
||||
if (invalidElements != null) {
|
||||
invalidElements.errorBefore(message("unexpected.token"), statement)
|
||||
invalidElements.errorBefore(JavaSyntaxBundle.message("unexpected.token"), statement)
|
||||
invalidElements = null
|
||||
}
|
||||
continue
|
||||
@@ -180,10 +182,11 @@ open class FileParser(private val myParser: JavaParser) {
|
||||
}
|
||||
|
||||
//if it is `module` we should expect either `;` or `identifier`
|
||||
if (isOk && !isModule && !isStatic && builder.tokenType !== JavaSyntaxTokenType.SEMICOLON &&
|
||||
if (isOk && !isModule &&
|
||||
!isStatic && builder.tokenType !== JavaSyntaxTokenType.SEMICOLON &&
|
||||
PsiKeyword.MODULE == identifierText
|
||||
) {
|
||||
JavaParserUtil.error(builder, message("expected.identifier.or.semicolon"))
|
||||
JavaParserUtil.error(builder, JavaSyntaxBundle.message("expected.identifier.or.semicolon"))
|
||||
}
|
||||
else if (isOk) {
|
||||
JavaParserUtil.semicolon(builder)
|
||||
@@ -209,9 +212,6 @@ open class FileParser(private val myParser: JavaParser) {
|
||||
return JavaSyntaxElementType.IMPORT_STATEMENT
|
||||
}
|
||||
|
||||
private fun error(bundle: ResourceBundle, errorMessageKey: String): @NlsContexts.ParsingError String {
|
||||
return bundle.message(errorMessageKey)
|
||||
}
|
||||
}
|
||||
|
||||
val IMPORT_LIST_STOPPER_SET: SyntaxElementTypeSet =
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.java.syntax.parser
|
||||
|
||||
import com.intellij.java.syntax.JavaSyntaxBundle
|
||||
import com.intellij.java.syntax.element.JShellSyntaxElementType
|
||||
import com.intellij.java.syntax.element.JavaSyntaxElementType
|
||||
import com.intellij.java.syntax.element.JavaSyntaxTokenType
|
||||
import com.intellij.java.syntax.element.SyntaxElementTypes
|
||||
import com.intellij.platform.syntax.SyntaxElementType
|
||||
import com.intellij.platform.syntax.SyntaxElementTypeSet
|
||||
import com.intellij.platform.syntax.parser.SyntaxTreeBuilder
|
||||
import com.intellij.platform.syntax.syntaxElementTypeSetOf
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
class JShellParser(languageLevel: LanguageLevel) : JavaParser(languageLevel) {
|
||||
override val fileParser: FileParser = object : FileParser(this) {
|
||||
override fun parse(builder: SyntaxTreeBuilder) {
|
||||
parseImportList(builder) { b -> b.tokenType in IMPORT_PARSING_STOP_LIST }
|
||||
|
||||
val rootClass: SyntaxTreeBuilder.Marker = builder.mark()
|
||||
try {
|
||||
while (!builder.eof()) {
|
||||
var wrapper: SyntaxTreeBuilder.Marker? = builder.mark()
|
||||
var wrapperType: SyntaxElementType? = null
|
||||
|
||||
var marker: SyntaxTreeBuilder.Marker? = parseImportStatement(builder)
|
||||
if (isParsed(marker, builder) { tokenType -> tokenType === JavaSyntaxElementType.IMPORT_STATEMENT }) {
|
||||
wrapperType = JShellSyntaxElementType.IMPORT_HOLDER
|
||||
}
|
||||
else {
|
||||
marker?.rollbackTo()
|
||||
marker = declarationParser.parse(builder, DeclarationParser.Context.JSHELL)
|
||||
if (isParsed(marker, builder) { tokenType -> tokenType in TOP_LEVEL_DECLARATIONS } &&
|
||||
!builder.hasErrorsAfter(marker)
|
||||
) {
|
||||
wrapper!!.drop() // don't need wrapper for top-level declaration
|
||||
wrapper = null
|
||||
}
|
||||
else {
|
||||
marker?.rollbackTo()
|
||||
marker = statementParser.parseStatement(builder)
|
||||
if (marker != null && !builder.hasErrorsAfter(marker)) {
|
||||
wrapperType = JShellSyntaxElementType.STATEMENTS_HOLDER
|
||||
}
|
||||
else {
|
||||
marker?.rollbackTo()
|
||||
marker = expressionParser.parse(builder)
|
||||
wrapperType = if (marker != null) JShellSyntaxElementType.STATEMENTS_HOLDER else null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (marker == null) {
|
||||
wrapper!!.drop()
|
||||
break
|
||||
}
|
||||
|
||||
wrapper?.done(wrapperType!!)
|
||||
}
|
||||
|
||||
if (!builder.eof()) {
|
||||
builder.mark().error(JavaSyntaxBundle.message("unexpected.token"))
|
||||
while (!builder.eof()) {
|
||||
builder.advanceLexer()
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
rootClass.done(JShellSyntaxElementType.ROOT_CLASS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun parse(builder: SyntaxTreeBuilder) {
|
||||
val root = builder.mark()
|
||||
fileParser.parse(builder)
|
||||
root.done(JShellSyntaxElementType.FILE)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
private fun isParsed(
|
||||
parsedMarker: SyntaxTreeBuilder.Marker?,
|
||||
builder: SyntaxTreeBuilder,
|
||||
cond: (SyntaxElementType) -> Boolean,
|
||||
): Boolean {
|
||||
contract {
|
||||
returns(true) implies (parsedMarker != null)
|
||||
}
|
||||
if (parsedMarker == null) return false
|
||||
val lastDone = builder.lastDoneMarker ?: return false
|
||||
return cond(lastDone.getNodeType())
|
||||
}
|
||||
}
|
||||
|
||||
private val TOP_LEVEL_DECLARATIONS: SyntaxElementTypeSet = syntaxElementTypeSetOf(
|
||||
JavaSyntaxElementType.FIELD,
|
||||
JavaSyntaxElementType.METHOD,
|
||||
JavaSyntaxElementType.CLASS
|
||||
)
|
||||
|
||||
private val IMPORT_PARSING_STOP_LIST: SyntaxElementTypeSet =
|
||||
IMPORT_LIST_STOPPER_SET +
|
||||
SyntaxElementTypes.MODIFIER_BIT_SET +
|
||||
SyntaxElementTypes.JAVA_COMMENT_BIT_SET +
|
||||
SyntaxElementTypes.EXPRESSION_BIT_SET +
|
||||
SyntaxElementTypes.JAVA_STATEMENT_BIT_SET +
|
||||
SyntaxElementTypes.PRIMITIVE_TYPE_BIT_SET +
|
||||
JShellSyntaxElementType.ROOT_CLASS +
|
||||
JavaSyntaxTokenType.IDENTIFIER
|
||||
|
||||
@@ -2,11 +2,16 @@
|
||||
package com.intellij.java.parser;
|
||||
|
||||
import com.intellij.JavaTestUtil;
|
||||
import com.intellij.java.frontback.psi.impl.syntax.JavaSyntaxDefinitionExtension;
|
||||
import com.intellij.lang.LanguageASTFactory;
|
||||
import com.intellij.lang.ParserDefinition;
|
||||
import com.intellij.lang.java.JShellLanguage;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.lang.java.syntax.JavaElementTypeConverterExtension;
|
||||
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
|
||||
import com.intellij.openapi.roots.impl.LanguageLevelProjectExtensionImpl;
|
||||
import com.intellij.platform.syntax.psi.ElementTypeConverters;
|
||||
import com.intellij.platform.syntax.psi.LanguageSyntaxDefinitions;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.impl.source.tree.JavaASTFactory;
|
||||
@@ -29,6 +34,8 @@ public abstract class JavaParsingTestCase extends ParsingTestCase {
|
||||
getProject().registerService(WorkspaceModelTopics.class, new WorkspaceModelTopics());
|
||||
getProject().registerService(LanguageLevelProjectExtension.class, new LanguageLevelProjectExtensionImpl(getProject()));
|
||||
addExplicitExtension(LanguageASTFactory.INSTANCE, JavaLanguage.INSTANCE, new JavaASTFactory());
|
||||
addExplicitExtension(LanguageSyntaxDefinitions.getINSTANCE(), JavaLanguage.INSTANCE, new JavaSyntaxDefinitionExtension());
|
||||
addExplicitExtension(ElementTypeConverters.getInstance(), JavaLanguage.INSTANCE, new JavaElementTypeConverterExtension());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,9 +2,17 @@
|
||||
package com.intellij.java.parser.jshell;
|
||||
|
||||
import com.intellij.ide.highlighter.JShellFileType;
|
||||
import com.intellij.java.frontback.psi.impl.syntax.JShellSyntaxDefinitionExtension;
|
||||
import com.intellij.java.frontback.psi.impl.syntax.JavaSyntaxDefinitionExtension;
|
||||
import com.intellij.java.parser.JavaParsingTestCase;
|
||||
import com.intellij.lang.java.JShellLanguage;
|
||||
import com.intellij.lang.java.JShellParserDefinition;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.lang.java.JavaParserDefinition;
|
||||
import com.intellij.lang.java.syntax.JShellElementTypeConverterExtension;
|
||||
import com.intellij.lang.java.syntax.JavaElementTypeConverterExtension;
|
||||
import com.intellij.platform.syntax.psi.ElementTypeConverters;
|
||||
import com.intellij.platform.syntax.psi.LanguageSyntaxDefinitions;
|
||||
|
||||
public class JShellParsingTest extends JavaParsingTestCase {
|
||||
|
||||
@@ -12,6 +20,14 @@ public class JShellParsingTest extends JavaParsingTestCase {
|
||||
super("parser-full/jshell", JShellFileType.DEFAULT_EXTENSION, new JShellParserDefinition(), new JavaParserDefinition());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
addExplicitExtension(ElementTypeConverters.getInstance(), JShellLanguage.INSTANCE, new JavaElementTypeConverterExtension());
|
||||
addExplicitExtension(ElementTypeConverters.getInstance(), JShellLanguage.INSTANCE, new JShellElementTypeConverterExtension());
|
||||
addExplicitExtension(LanguageSyntaxDefinitions.getINSTANCE(), JShellLanguage.INSTANCE, new JShellSyntaxDefinitionExtension());
|
||||
}
|
||||
|
||||
public void testClass0() { doTest(); }
|
||||
public void testStatement0() { doTest(); }
|
||||
public void testStatement1() { doTest(); }
|
||||
|
||||
Reference in New Issue
Block a user