Local declarations
This commit is contained in:
@@ -102,9 +102,20 @@ import static org.jetbrains.jet.lexer.JetTokens.*;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (expectation == IDENTIFIER && token instanceof JetKeywordToken) {
|
||||
JetKeywordToken keywordToken = (JetKeywordToken) token;
|
||||
if (keywordToken.isSoft()) {
|
||||
myBuilder.remapCurrentToken(IDENTIFIER);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean atSet(IElementType... tokens) {
|
||||
return atSet(TokenSet.create(tokens));
|
||||
}
|
||||
|
||||
protected boolean atSet(final TokenSet set) {
|
||||
IElementType token = tt();
|
||||
if (set.contains(token)) return true;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.jetbrains.jet.lang.parsing;
|
||||
|
||||
import com.intellij.lang.PsiBuilder;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import org.jetbrains.jet.JetNodeType;
|
||||
|
||||
@@ -106,19 +107,21 @@ public class JetExpressionParsing extends AbstractJetParsing {
|
||||
else if (at(NULL_KEYWORD)) {
|
||||
parseOneTokenExpression(NULL);
|
||||
}
|
||||
else if (atSet(TokenSet.create(
|
||||
CLASS_KEYWORD,
|
||||
EXTENSION_KEYWORD,
|
||||
FUN_KEYWORD,
|
||||
VAL_KEYWORD,
|
||||
VAR_KEYWORD,
|
||||
TYPE_KEYWORD))) {
|
||||
// modifiers
|
||||
// attributes
|
||||
// TODO
|
||||
else if (atSet(CLASS_KEYWORD, EXTENSION_KEYWORD, FUN_KEYWORD, VAL_KEYWORD,
|
||||
VAR_KEYWORD, TYPE_KEYWORD, DECOMPOSER_KEYWORD)) {
|
||||
parseLocalDeclaration();
|
||||
}
|
||||
else if (at(LBRACKET)) {
|
||||
if (!parseLocalDeclaration()) {
|
||||
PsiBuilder.Marker attributes = mark();
|
||||
myJetParsing.parseAttributeList();
|
||||
attributes.error("Attributes are only allowed on declarations");
|
||||
}
|
||||
}
|
||||
else if (at(IDENTIFIER)) {
|
||||
advance(); // TODO
|
||||
if (!parseLocalDeclaration()) {
|
||||
expect(IDENTIFIER, "[Internal error: should never occur]"); // TODO
|
||||
}
|
||||
}
|
||||
else if (at(LBRACE)) {
|
||||
// TODO
|
||||
@@ -131,6 +134,47 @@ public class JetExpressionParsing extends AbstractJetParsing {
|
||||
// TODO: Binary operations
|
||||
}
|
||||
|
||||
private boolean parseLocalDeclaration() {
|
||||
PsiBuilder.Marker decls = mark();
|
||||
JetParsing.EnumDetector enumDetector = new JetParsing.EnumDetector();
|
||||
myJetParsing.parseModifierList(enumDetector);
|
||||
|
||||
JetNodeType declType = parseLocalDeclarationRest(enumDetector.isEnum());
|
||||
|
||||
if (declType != null) {
|
||||
decls.done(declType);
|
||||
return true;
|
||||
} else {
|
||||
decls.rollbackTo();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private JetNodeType parseLocalDeclarationRest(boolean isEnum) {
|
||||
IElementType keywordToken = tt();
|
||||
JetNodeType declType = null;
|
||||
if (keywordToken == CLASS_KEYWORD) {
|
||||
declType = myJetParsing.parseClass(isEnum);
|
||||
}
|
||||
else if (keywordToken == EXTENSION_KEYWORD) {
|
||||
declType = myJetParsing.parseExtension();
|
||||
}
|
||||
else if (keywordToken == FUN_KEYWORD) {
|
||||
declType = myJetParsing.parseFunction();
|
||||
}
|
||||
else if (keywordToken == VAL_KEYWORD || keywordToken == VAR_KEYWORD) {
|
||||
declType = myJetParsing.parseProperty();
|
||||
}
|
||||
else if (keywordToken == TYPE_KEYWORD) {
|
||||
declType = myJetParsing.parseTypeDef();
|
||||
}
|
||||
else if (keywordToken == DECOMPOSER_KEYWORD) {
|
||||
declType = myJetParsing.parseDecomposer();
|
||||
}
|
||||
return declType;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* doWhile
|
||||
* : "do" expression "while" "(" expression ")"
|
||||
|
||||
@@ -213,7 +213,7 @@ public class JetParsing extends AbstractJetParsing {
|
||||
* : modifiers "decomposer" (type ".")? SimpleName? "(" (attributes SimpleName){","}? ")" // Public properties only
|
||||
* ;
|
||||
*/
|
||||
private JetNodeType parseDecomposer() {
|
||||
public JetNodeType parseDecomposer() {
|
||||
assert at(DECOMPOSER_KEYWORD);
|
||||
advance(); // DECOMPOSER_KEYWORD
|
||||
|
||||
@@ -274,7 +274,7 @@ public class JetParsing extends AbstractJetParsing {
|
||||
/*
|
||||
* (modifier | attribute)*
|
||||
*/
|
||||
private void parseModifierList() {
|
||||
public void parseModifierList() {
|
||||
parseModifierList(null);
|
||||
}
|
||||
|
||||
@@ -283,7 +283,7 @@ public class JetParsing extends AbstractJetParsing {
|
||||
*
|
||||
* Feeds modifiers (not attributes) into the passed consumer, if it is not null
|
||||
*/
|
||||
private void parseModifierList(Consumer<IElementType> tokenConsumer) {
|
||||
public void parseModifierList(Consumer<IElementType> tokenConsumer) {
|
||||
PsiBuilder.Marker list = mark();
|
||||
boolean empty = true;
|
||||
while (!eof()) {
|
||||
@@ -391,7 +391,7 @@ public class JetParsing extends AbstractJetParsing {
|
||||
* (classBody? | enumClassBody)
|
||||
* ;
|
||||
*/
|
||||
private JetNodeType parseClass(boolean enumClass) {
|
||||
public JetNodeType parseClass(boolean enumClass) {
|
||||
assert at(CLASS_KEYWORD);
|
||||
advance(); // CLASS_KEYWORD
|
||||
|
||||
@@ -664,7 +664,7 @@ public class JetParsing extends AbstractJetParsing {
|
||||
* : modifiers "type" SimpleName typeParameters? "=" type
|
||||
* ;
|
||||
*/
|
||||
private JetNodeType parseTypeDef() {
|
||||
public JetNodeType parseTypeDef() {
|
||||
assert at(TYPE_KEYWORD);
|
||||
|
||||
advance(); // TYPE_KEYWORD
|
||||
@@ -688,32 +688,31 @@ public class JetParsing extends AbstractJetParsing {
|
||||
* (getter? setter? | setter? getter?) SEMI?
|
||||
* ;
|
||||
*/
|
||||
private JetNodeType parseProperty() {
|
||||
public JetNodeType parseProperty() {
|
||||
assert at(VAL_KEYWORD) || at(VAR_KEYWORD);
|
||||
|
||||
advance(); // VAL_KEYWORD or VAR_KEYWORD
|
||||
|
||||
// TODO: EOL_OR_SEMICOLON is too restrictive here
|
||||
TokenSet propertyNameFollow = TokenSet.create(COLON, EQ, LBRACE, SEMICOLON);
|
||||
|
||||
// int lastDot = findLastBefore(TokenSet.create(DOT), propertyNameFollow, true);
|
||||
// TODO: constant
|
||||
int lastDot = matchTokenStreamPredicate(new FirstBefore(new TokenStreamPredicate() {
|
||||
@Override
|
||||
public boolean matching(boolean topLevel) {
|
||||
return topLevel
|
||||
&& at(DOT);
|
||||
}
|
||||
}, new TokenStreamPredicate() {
|
||||
@Override
|
||||
public boolean matching(boolean topLevel) {
|
||||
if (lookahead(1) == IDENTIFIER) {
|
||||
IElementType lookahead2 = lookahead(2);
|
||||
return lookahead2 != LT && lookahead2 != DOT;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
int lastDot = matchTokenStreamPredicate(new FirstBefore(
|
||||
new TokenStreamPredicate() {
|
||||
@Override
|
||||
public boolean matching(boolean topLevel) {
|
||||
return topLevel
|
||||
&& at(DOT);
|
||||
}
|
||||
}, new TokenStreamPredicate() {
|
||||
@Override
|
||||
public boolean matching(boolean topLevel) {
|
||||
if (lookahead(1) == IDENTIFIER) {
|
||||
IElementType lookahead2 = lookahead(2);
|
||||
return lookahead2 != LT && lookahead2 != DOT;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
|
||||
if (lastDot == -1) {
|
||||
parseAttributeList();
|
||||
@@ -806,7 +805,7 @@ public class JetParsing extends AbstractJetParsing {
|
||||
* : attributes SimpleName typeParameters? functionParameters (":" type)? functionBody?
|
||||
* ;
|
||||
*/
|
||||
private JetNodeType parseFunction() {
|
||||
public JetNodeType parseFunction() {
|
||||
assert at(FUN_KEYWORD);
|
||||
|
||||
advance(); // FUN_KEYWORD
|
||||
@@ -892,7 +891,7 @@ public class JetParsing extends AbstractJetParsing {
|
||||
* : modifiers "extension" SimpleName? typeParameters? "for" type classBody? // properties cannot be lazy, cannot have backing fields
|
||||
* ;
|
||||
*/
|
||||
private JetNodeType parseExtension() {
|
||||
public JetNodeType parseExtension() {
|
||||
assert at(EXTENSION_KEYWORD);
|
||||
|
||||
advance(); // EXTENSION_KEYWORD
|
||||
@@ -975,7 +974,7 @@ public class JetParsing extends AbstractJetParsing {
|
||||
* : attributeAnnotation*
|
||||
* ;
|
||||
*/
|
||||
private void parseAttributeList() {
|
||||
public void parseAttributeList() {
|
||||
while (at(LBRACKET)) parseAttributeAnnotation();
|
||||
}
|
||||
|
||||
@@ -1382,7 +1381,7 @@ public class JetParsing extends AbstractJetParsing {
|
||||
return new JetParsing(new TruncatedSemanticWhitespaceAwarePsiBuilder(myBuilder, eofPosition));
|
||||
}
|
||||
|
||||
private static class EnumDetector implements Consumer<IElementType> {
|
||||
/*package*/ static class EnumDetector implements Consumer<IElementType> {
|
||||
|
||||
private boolean myEnum = false;
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
fun foo() {
|
||||
lazy
|
||||
1
|
||||
[a] abstract class foof {}
|
||||
abstract [a] class foof {}
|
||||
|
||||
lazy val foo = 5
|
||||
[a] var foo = 4
|
||||
type f = {T.() : ()}
|
||||
|
||||
virtual extension foo for bar {
|
||||
|
||||
}
|
||||
|
||||
decomposer T.foo(bar)
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
JetFile: LocalDeclarations.jet
|
||||
NAMESPACE
|
||||
FUN
|
||||
PsiElement(fun)('fun')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(IDENTIFIER)('foo')
|
||||
TYPE_PARAMETER_LIST
|
||||
<empty list>
|
||||
VALUE_PARAMETER_LIST
|
||||
PsiElement(LPAR)('(')
|
||||
PsiElement(RPAR)(')')
|
||||
PsiWhiteSpace(' ')
|
||||
BLOCK
|
||||
PsiElement(LBRACE)('{')
|
||||
PsiWhiteSpace('\n ')
|
||||
PsiElement(IDENTIFIER)('lazy')
|
||||
PsiWhiteSpace('\n ')
|
||||
INTEGER_CONSTANT
|
||||
PsiElement(INTEGER_LITERAL)('1')
|
||||
PsiWhiteSpace('\n ')
|
||||
CLASS
|
||||
MODIFIER_LIST
|
||||
ATTRIBUTE_ANNOTATION
|
||||
PsiElement(LBRACKET)('[')
|
||||
ATTRIBUTE
|
||||
USER_TYPE
|
||||
PsiElement(IDENTIFIER)('a')
|
||||
PsiElement(RBRACKET)(']')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(abstract)('abstract')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(class)('class')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(IDENTIFIER)('foof')
|
||||
PsiWhiteSpace(' ')
|
||||
TYPE_PARAMETER_LIST
|
||||
<empty list>
|
||||
CLASS_BODY
|
||||
PsiElement(LBRACE)('{')
|
||||
PsiElement(RBRACE)('}')
|
||||
PsiWhiteSpace('\n ')
|
||||
CLASS
|
||||
MODIFIER_LIST
|
||||
PsiElement(abstract)('abstract')
|
||||
PsiWhiteSpace(' ')
|
||||
ATTRIBUTE_ANNOTATION
|
||||
PsiElement(LBRACKET)('[')
|
||||
ATTRIBUTE
|
||||
USER_TYPE
|
||||
PsiElement(IDENTIFIER)('a')
|
||||
PsiElement(RBRACKET)(']')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(class)('class')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(IDENTIFIER)('foof')
|
||||
PsiWhiteSpace(' ')
|
||||
TYPE_PARAMETER_LIST
|
||||
<empty list>
|
||||
CLASS_BODY
|
||||
PsiElement(LBRACE)('{')
|
||||
PsiElement(RBRACE)('}')
|
||||
PsiWhiteSpace('\n\n ')
|
||||
PROPERTY
|
||||
MODIFIER_LIST
|
||||
PsiElement(lazy)('lazy')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(val)('val')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(IDENTIFIER)('foo')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
INTEGER_CONSTANT
|
||||
PsiElement(INTEGER_LITERAL)('5')
|
||||
PsiWhiteSpace('\n ')
|
||||
PROPERTY
|
||||
MODIFIER_LIST
|
||||
ATTRIBUTE_ANNOTATION
|
||||
PsiElement(LBRACKET)('[')
|
||||
ATTRIBUTE
|
||||
USER_TYPE
|
||||
PsiElement(IDENTIFIER)('a')
|
||||
PsiElement(RBRACKET)(']')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(var)('var')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(IDENTIFIER)('foo')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
INTEGER_CONSTANT
|
||||
PsiElement(INTEGER_LITERAL)('4')
|
||||
PsiWhiteSpace('\n ')
|
||||
TYPEDEF
|
||||
PsiElement(type)('type')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(IDENTIFIER)('f')
|
||||
PsiWhiteSpace(' ')
|
||||
TYPE_PARAMETER_LIST
|
||||
<empty list>
|
||||
PsiElement(EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
TYPE_REFERENCE
|
||||
FUNCTION_TYPE
|
||||
PsiElement(LBRACE)('{')
|
||||
RECEIVER_TYPE
|
||||
TYPE_REFERENCE
|
||||
USER_TYPE
|
||||
PsiElement(IDENTIFIER)('T')
|
||||
PsiElement(DOT)('.')
|
||||
VALUE_PARAMETER_LIST
|
||||
PsiElement(LPAR)('(')
|
||||
PsiElement(RPAR)(')')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(COLON)(':')
|
||||
PsiWhiteSpace(' ')
|
||||
TYPE_REFERENCE
|
||||
TUPLE_TYPE
|
||||
PsiElement(LPAR)('(')
|
||||
PsiElement(RPAR)(')')
|
||||
PsiElement(RBRACE)('}')
|
||||
PsiWhiteSpace('\n\n ')
|
||||
EXTENSION
|
||||
MODIFIER_LIST
|
||||
PsiElement(virtual)('virtual')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(extension)('extension')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(IDENTIFIER)('foo')
|
||||
PsiWhiteSpace(' ')
|
||||
TYPE_PARAMETER_LIST
|
||||
<empty list>
|
||||
PsiElement(for)('for')
|
||||
PsiWhiteSpace(' ')
|
||||
TYPE_REFERENCE
|
||||
USER_TYPE
|
||||
PsiElement(IDENTIFIER)('bar')
|
||||
PsiWhiteSpace(' ')
|
||||
CLASS_BODY
|
||||
PsiElement(LBRACE)('{')
|
||||
PsiWhiteSpace('\n\n ')
|
||||
PsiElement(RBRACE)('}')
|
||||
PsiWhiteSpace('\n\n ')
|
||||
DECOMPOSER
|
||||
PsiElement(decomposer)('decomposer')
|
||||
PsiWhiteSpace(' ')
|
||||
TYPE_REFERENCE
|
||||
USER_TYPE
|
||||
PsiElement(IDENTIFIER)('T')
|
||||
PsiElement(DOT)('.')
|
||||
USER_TYPE
|
||||
PsiElement(IDENTIFIER)('foo')
|
||||
DECOMPOSER_PROPERTY_LIST
|
||||
PsiElement(LPAR)('(')
|
||||
PsiElement(IDENTIFIER)('bar')
|
||||
PsiElement(RPAR)(')')
|
||||
PsiWhiteSpace('\n')
|
||||
PsiElement(RBRACE)('}')
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo() {
|
||||
[a]
|
||||
1
|
||||
[a]
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
JetFile: LocalDeclarations_ERR.jet
|
||||
NAMESPACE
|
||||
FUN
|
||||
PsiElement(fun)('fun')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(IDENTIFIER)('foo')
|
||||
TYPE_PARAMETER_LIST
|
||||
<empty list>
|
||||
VALUE_PARAMETER_LIST
|
||||
PsiElement(LPAR)('(')
|
||||
PsiElement(RPAR)(')')
|
||||
PsiWhiteSpace(' ')
|
||||
BLOCK
|
||||
PsiElement(LBRACE)('{')
|
||||
PsiWhiteSpace('\n ')
|
||||
PsiErrorElement:Attributes are only allowed on declarations
|
||||
ATTRIBUTE_ANNOTATION
|
||||
PsiElement(LBRACKET)('[')
|
||||
ATTRIBUTE
|
||||
USER_TYPE
|
||||
PsiElement(IDENTIFIER)('a')
|
||||
PsiElement(RBRACKET)(']')
|
||||
PsiWhiteSpace('\n ')
|
||||
INTEGER_CONSTANT
|
||||
PsiElement(INTEGER_LITERAL)('1')
|
||||
PsiWhiteSpace('\n ')
|
||||
PsiErrorElement:Attributes are only allowed on declarations
|
||||
ATTRIBUTE_ANNOTATION
|
||||
PsiElement(LBRACKET)('[')
|
||||
ATTRIBUTE
|
||||
USER_TYPE
|
||||
PsiElement(IDENTIFIER)('a')
|
||||
PsiElement(RBRACKET)(']')
|
||||
PsiWhiteSpace('\n')
|
||||
PsiElement(RBRACE)('}')
|
||||
@@ -47,6 +47,8 @@ public class JetParsingTest extends ParsingTestCase {
|
||||
public void testImports() throws Exception {doTest(true);}
|
||||
public void testImports_ERR() throws Exception {doTest(true);}
|
||||
public void testImportSoftKW() throws Exception {doTest(true);}
|
||||
public void testLocalDeclarations() throws Exception {doTest(true);}
|
||||
public void testLocalDeclarations_ERR() throws Exception {doTest(true);}
|
||||
public void testNamespaceBlock_ERR() throws Exception {doTest(true);}
|
||||
public void testNamespaceBlock() throws Exception {doTest(true);}
|
||||
public void testProperties() throws Exception {doTest(true);}
|
||||
|
||||
Reference in New Issue
Block a user