From 2e837c6586af6a312044d19f8fd7d34366ddba28 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Mon, 19 Jan 2015 19:38:06 +0300 Subject: [PATCH] Parser: allow names to be specified for class objects --- .../kotlin/parsing/JetExpressionParsing.java | 5 +- .../jetbrains/kotlin/parsing/JetParsing.java | 38 +++++++++---- compiler/testData/psi/NamedClassObject.kt | 11 ++++ compiler/testData/psi/NamedClassObject.txt | 55 +++++++++++++++++++ .../parsing/JetParsingTestGenerated.java | 6 ++ 5 files changed, 101 insertions(+), 14 deletions(-) create mode 100644 compiler/testData/psi/NamedClassObject.kt create mode 100644 compiler/testData/psi/NamedClassObject.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetExpressionParsing.java b/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetExpressionParsing.java index 5bab703e121..d1212ddc30d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetExpressionParsing.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetExpressionParsing.java @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.JetNodeType; import org.jetbrains.kotlin.JetNodeTypes; import org.jetbrains.kotlin.lexer.JetToken; import org.jetbrains.kotlin.lexer.JetTokens; +import org.jetbrains.kotlin.parsing.JetParsing.NameParsingMode; import java.util.Arrays; import java.util.HashSet; @@ -1318,7 +1319,7 @@ public class JetExpressionParsing extends AbstractJetParsing { return null; } - myJetParsing.parseObject(true, true); + myJetParsing.parseObject(NameParsingMode.REQUIRED, true); declType = OBJECT_DECLARATION; } return declType; @@ -1826,7 +1827,7 @@ public class JetExpressionParsing extends AbstractJetParsing { public void parseObjectLiteral() { PsiBuilder.Marker literal = mark(); PsiBuilder.Marker declaration = mark(); - myJetParsing.parseObject(false, false); // Body is not optional because of foo(object : A, B) + myJetParsing.parseObject(NameParsingMode.PROHIBITED, false); // Body is not optional because of foo(object : A, B) declaration.done(OBJECT_DECLARATION); literal.done(OBJECT_LITERAL); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetParsing.java b/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetParsing.java index c2d23aa7a2b..4982fa5590f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetParsing.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetParsing.java @@ -376,7 +376,7 @@ public class JetParsing extends AbstractJetParsing { declType = parseTypeAlias(); } else if (keywordToken == OBJECT_KEYWORD) { - parseObject(true, true); + parseObject(NameParsingMode.REQUIRED, true); declType = OBJECT_DECLARATION; } @@ -551,6 +551,12 @@ public class JetParsing extends AbstractJetParsing { annotation.done(ANNOTATION_ENTRY); } + public enum NameParsingMode { + REQUIRED, + ALLOWED, + PROHIBITED; + } + /* * class * : modifiers ("class" | "trait") SimpleName @@ -565,7 +571,7 @@ public class JetParsing extends AbstractJetParsing { * : "object" SimpleName? ":" delegationSpecifier{","}? classBody? * ; */ - IElementType parseClassOrObject(final boolean object, boolean named, boolean optionalBody, boolean enumClass) { + IElementType parseClassOrObject(boolean object, NameParsingMode nameParsingMode, boolean optionalBody, boolean enumClass) { if (object) { assert _at(OBJECT_KEYWORD); } @@ -574,15 +580,23 @@ public class JetParsing extends AbstractJetParsing { } advance(); // CLASS_KEYWORD, TRAIT_KEYWORD or OBJECT_KEYWORD - if (named) { + if (nameParsingMode == NameParsingMode.REQUIRED) { OptionalMarker marker = new OptionalMarker(object); expect(IDENTIFIER, "Name expected", CLASS_NAME_RECOVERY_SET); marker.done(OBJECT_DECLARATION_NAME); } else { + assert object : "Must be an object to be nameless"; if (at(IDENTIFIER)) { - assert object : "Must be an object to be nameless"; - errorAndAdvance("An object expression cannot bind a name"); + if (nameParsingMode == NameParsingMode.PROHIBITED) { + errorAndAdvance("An object expression cannot bind a name"); + } + else { + assert nameParsingMode == NameParsingMode.ALLOWED; + PsiBuilder.Marker marker = mark(); + advance(); + marker.done(OBJECT_DECLARATION_NAME); + } } } @@ -595,7 +609,7 @@ public class JetParsing extends AbstractJetParsing { boolean hasConstructorModifiers = parseModifierList(PRIMARY_CONSTRUCTOR_MODIFIER_LIST, REGULAR_ANNOTATIONS_ONLY_WITH_BRACKETS); // Some modifiers found, but no parentheses following: class has already ended, and we are looking at something else - if (hasConstructorModifiers && !atSet(LPAR, LBRACE, COLON) ) { + if (hasConstructorModifiers && !atSet(LPAR, LBRACE, COLON)) { beforeConstructorModifiers.rollbackTo(); constructorModifiersMarker.drop(); return object ? OBJECT_DECLARATION : CLASS; @@ -616,7 +630,7 @@ public class JetParsing extends AbstractJetParsing { } constructorModifiersMarker.error("Constructors are not allowed for objects"); - if (at(COLON) ) { + if (at(COLON)) { advance(); // COLON parseDelegationSpecifierList(); } @@ -643,11 +657,11 @@ public class JetParsing extends AbstractJetParsing { } IElementType parseClass(boolean enumClass) { - return parseClassOrObject(false, true, true, enumClass); + return parseClassOrObject(false, NameParsingMode.REQUIRED, true, enumClass); } - void parseObject(boolean named, boolean optionalBody) { - parseClassOrObject(true, named, optionalBody, false); + void parseObject(NameParsingMode nameParsingMode, boolean optionalBody) { + parseClassOrObject(true, nameParsingMode, optionalBody, false); } /* @@ -803,7 +817,7 @@ public class JetParsing extends AbstractJetParsing { declType = parseTypeAlias(); } else if (keywordToken == OBJECT_KEYWORD) { - parseObject(true, true); + parseObject(NameParsingMode.REQUIRED, true); declType = OBJECT_DECLARATION; } else if (keywordToken == LBRACE) { @@ -872,7 +886,7 @@ public class JetParsing extends AbstractJetParsing { advance(); // CLASS_KEYWORD PsiBuilder.Marker objectDeclaration = mark(); - parseObject(false, true); + parseObject(NameParsingMode.ALLOWED, true); closeDeclarationWithCommentBinders(objectDeclaration, OBJECT_DECLARATION, true); return CLASS_OBJECT; } diff --git a/compiler/testData/psi/NamedClassObject.kt b/compiler/testData/psi/NamedClassObject.kt new file mode 100644 index 00000000000..83bfa32b495 --- /dev/null +++ b/compiler/testData/psi/NamedClassObject.kt @@ -0,0 +1,11 @@ +class A { + class object Default + + class object B + + class object C {} + + class object + + object C +} diff --git a/compiler/testData/psi/NamedClassObject.txt b/compiler/testData/psi/NamedClassObject.txt new file mode 100644 index 00000000000..8e1dcd4ccb1 --- /dev/null +++ b/compiler/testData/psi/NamedClassObject.txt @@ -0,0 +1,55 @@ +JetFile: NamedClassObject.kt + PACKAGE_DIRECTIVE + + CLASS + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('A') + PsiWhiteSpace(' ') + CLASS_BODY + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + CLASS_OBJECT + PsiElement(class)('class') + PsiWhiteSpace(' ') + OBJECT_DECLARATION + PsiElement(object)('object') + PsiWhiteSpace(' ') + OBJECT_DECLARATION_NAME + PsiElement(IDENTIFIER)('Default') + PsiWhiteSpace('\n\n ') + CLASS_OBJECT + PsiElement(class)('class') + PsiWhiteSpace(' ') + OBJECT_DECLARATION + PsiElement(object)('object') + PsiWhiteSpace(' ') + OBJECT_DECLARATION_NAME + PsiElement(IDENTIFIER)('B') + PsiWhiteSpace('\n\n ') + CLASS_OBJECT + PsiElement(class)('class') + PsiWhiteSpace(' ') + OBJECT_DECLARATION + PsiElement(object)('object') + PsiWhiteSpace(' ') + OBJECT_DECLARATION_NAME + PsiElement(IDENTIFIER)('C') + PsiWhiteSpace(' ') + CLASS_BODY + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + CLASS_OBJECT + PsiElement(class)('class') + PsiWhiteSpace(' ') + OBJECT_DECLARATION + PsiElement(object)('object') + PsiWhiteSpace('\n\n ') + OBJECT_DECLARATION + PsiElement(object)('object') + PsiWhiteSpace(' ') + OBJECT_DECLARATION_NAME + PsiElement(IDENTIFIER)('C') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/parsing/JetParsingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/parsing/JetParsingTestGenerated.java index 8f68e5506d3..ffd1a46a80a 100644 --- a/compiler/tests/org/jetbrains/kotlin/parsing/JetParsingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/parsing/JetParsingTestGenerated.java @@ -370,6 +370,12 @@ public class JetParsingTestGenerated extends AbstractJetParsingTest { doParsingTest(fileName); } + @TestMetadata("NamedClassObject.kt") + public void testNamedClassObject() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/NamedClassObject.kt"); + doParsingTest(fileName); + } + @TestMetadata("NestedComments.kt") public void testNestedComments() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/NestedComments.kt");