Parser: allow names to be specified for class objects
This commit is contained in:
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.JetNodeType;
|
|||||||
import org.jetbrains.kotlin.JetNodeTypes;
|
import org.jetbrains.kotlin.JetNodeTypes;
|
||||||
import org.jetbrains.kotlin.lexer.JetToken;
|
import org.jetbrains.kotlin.lexer.JetToken;
|
||||||
import org.jetbrains.kotlin.lexer.JetTokens;
|
import org.jetbrains.kotlin.lexer.JetTokens;
|
||||||
|
import org.jetbrains.kotlin.parsing.JetParsing.NameParsingMode;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -1318,7 +1319,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
myJetParsing.parseObject(true, true);
|
myJetParsing.parseObject(NameParsingMode.REQUIRED, true);
|
||||||
declType = OBJECT_DECLARATION;
|
declType = OBJECT_DECLARATION;
|
||||||
}
|
}
|
||||||
return declType;
|
return declType;
|
||||||
@@ -1826,7 +1827,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
|
|||||||
public void parseObjectLiteral() {
|
public void parseObjectLiteral() {
|
||||||
PsiBuilder.Marker literal = mark();
|
PsiBuilder.Marker literal = mark();
|
||||||
PsiBuilder.Marker declaration = 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);
|
declaration.done(OBJECT_DECLARATION);
|
||||||
literal.done(OBJECT_LITERAL);
|
literal.done(OBJECT_LITERAL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -376,7 +376,7 @@ public class JetParsing extends AbstractJetParsing {
|
|||||||
declType = parseTypeAlias();
|
declType = parseTypeAlias();
|
||||||
}
|
}
|
||||||
else if (keywordToken == OBJECT_KEYWORD) {
|
else if (keywordToken == OBJECT_KEYWORD) {
|
||||||
parseObject(true, true);
|
parseObject(NameParsingMode.REQUIRED, true);
|
||||||
declType = OBJECT_DECLARATION;
|
declType = OBJECT_DECLARATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -551,6 +551,12 @@ public class JetParsing extends AbstractJetParsing {
|
|||||||
annotation.done(ANNOTATION_ENTRY);
|
annotation.done(ANNOTATION_ENTRY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum NameParsingMode {
|
||||||
|
REQUIRED,
|
||||||
|
ALLOWED,
|
||||||
|
PROHIBITED;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* class
|
* class
|
||||||
* : modifiers ("class" | "trait") SimpleName
|
* : modifiers ("class" | "trait") SimpleName
|
||||||
@@ -565,7 +571,7 @@ public class JetParsing extends AbstractJetParsing {
|
|||||||
* : "object" SimpleName? ":" delegationSpecifier{","}? classBody?
|
* : "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) {
|
if (object) {
|
||||||
assert _at(OBJECT_KEYWORD);
|
assert _at(OBJECT_KEYWORD);
|
||||||
}
|
}
|
||||||
@@ -574,15 +580,23 @@ public class JetParsing extends AbstractJetParsing {
|
|||||||
}
|
}
|
||||||
advance(); // CLASS_KEYWORD, TRAIT_KEYWORD or OBJECT_KEYWORD
|
advance(); // CLASS_KEYWORD, TRAIT_KEYWORD or OBJECT_KEYWORD
|
||||||
|
|
||||||
if (named) {
|
if (nameParsingMode == NameParsingMode.REQUIRED) {
|
||||||
OptionalMarker marker = new OptionalMarker(object);
|
OptionalMarker marker = new OptionalMarker(object);
|
||||||
expect(IDENTIFIER, "Name expected", CLASS_NAME_RECOVERY_SET);
|
expect(IDENTIFIER, "Name expected", CLASS_NAME_RECOVERY_SET);
|
||||||
marker.done(OBJECT_DECLARATION_NAME);
|
marker.done(OBJECT_DECLARATION_NAME);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
assert object : "Must be an object to be nameless";
|
||||||
if (at(IDENTIFIER)) {
|
if (at(IDENTIFIER)) {
|
||||||
assert object : "Must be an object to be nameless";
|
if (nameParsingMode == NameParsingMode.PROHIBITED) {
|
||||||
errorAndAdvance("An object expression cannot bind a name");
|
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);
|
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
|
// 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();
|
beforeConstructorModifiers.rollbackTo();
|
||||||
constructorModifiersMarker.drop();
|
constructorModifiersMarker.drop();
|
||||||
return object ? OBJECT_DECLARATION : CLASS;
|
return object ? OBJECT_DECLARATION : CLASS;
|
||||||
@@ -616,7 +630,7 @@ public class JetParsing extends AbstractJetParsing {
|
|||||||
}
|
}
|
||||||
constructorModifiersMarker.error("Constructors are not allowed for objects");
|
constructorModifiersMarker.error("Constructors are not allowed for objects");
|
||||||
|
|
||||||
if (at(COLON) ) {
|
if (at(COLON)) {
|
||||||
advance(); // COLON
|
advance(); // COLON
|
||||||
parseDelegationSpecifierList();
|
parseDelegationSpecifierList();
|
||||||
}
|
}
|
||||||
@@ -643,11 +657,11 @@ public class JetParsing extends AbstractJetParsing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IElementType parseClass(boolean enumClass) {
|
IElementType parseClass(boolean enumClass) {
|
||||||
return parseClassOrObject(false, true, true, enumClass);
|
return parseClassOrObject(false, NameParsingMode.REQUIRED, true, enumClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
void parseObject(boolean named, boolean optionalBody) {
|
void parseObject(NameParsingMode nameParsingMode, boolean optionalBody) {
|
||||||
parseClassOrObject(true, named, optionalBody, false);
|
parseClassOrObject(true, nameParsingMode, optionalBody, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -803,7 +817,7 @@ public class JetParsing extends AbstractJetParsing {
|
|||||||
declType = parseTypeAlias();
|
declType = parseTypeAlias();
|
||||||
}
|
}
|
||||||
else if (keywordToken == OBJECT_KEYWORD) {
|
else if (keywordToken == OBJECT_KEYWORD) {
|
||||||
parseObject(true, true);
|
parseObject(NameParsingMode.REQUIRED, true);
|
||||||
declType = OBJECT_DECLARATION;
|
declType = OBJECT_DECLARATION;
|
||||||
}
|
}
|
||||||
else if (keywordToken == LBRACE) {
|
else if (keywordToken == LBRACE) {
|
||||||
@@ -872,7 +886,7 @@ public class JetParsing extends AbstractJetParsing {
|
|||||||
advance(); // CLASS_KEYWORD
|
advance(); // CLASS_KEYWORD
|
||||||
|
|
||||||
PsiBuilder.Marker objectDeclaration = mark();
|
PsiBuilder.Marker objectDeclaration = mark();
|
||||||
parseObject(false, true);
|
parseObject(NameParsingMode.ALLOWED, true);
|
||||||
closeDeclarationWithCommentBinders(objectDeclaration, OBJECT_DECLARATION, true);
|
closeDeclarationWithCommentBinders(objectDeclaration, OBJECT_DECLARATION, true);
|
||||||
return CLASS_OBJECT;
|
return CLASS_OBJECT;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
class A {
|
||||||
|
class object Default
|
||||||
|
|
||||||
|
class object B
|
||||||
|
|
||||||
|
class object C {}
|
||||||
|
|
||||||
|
class object
|
||||||
|
|
||||||
|
object C
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
JetFile: NamedClassObject.kt
|
||||||
|
PACKAGE_DIRECTIVE
|
||||||
|
<empty list>
|
||||||
|
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)('}')
|
||||||
@@ -370,6 +370,12 @@ public class JetParsingTestGenerated extends AbstractJetParsingTest {
|
|||||||
doParsingTest(fileName);
|
doParsingTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("NamedClassObject.kt")
|
||||||
|
public void testNamedClassObject() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/NamedClassObject.kt");
|
||||||
|
doParsingTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("NestedComments.kt")
|
@TestMetadata("NestedComments.kt")
|
||||||
public void testNestedComments() throws Exception {
|
public void testNestedComments() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/NestedComments.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/NestedComments.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user