Script refactoring, parser: wrap statements in script as if they are init blocks of a class

This commit is contained in:
Pavel V. Talanov
2015-11-17 15:03:21 +03:00
parent e45585be21
commit daa1a08213
9 changed files with 154 additions and 116 deletions
@@ -1181,13 +1181,21 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
* : SEMI* statement{SEMI+} SEMI* * : SEMI* statement{SEMI+} SEMI*
*/ */
public void parseStatements() { public void parseStatements() {
parseStatements(false);
}
/*
* expressions
* : SEMI* statement{SEMI+} SEMI*
*/
public void parseStatements(boolean isScriptTopLevel) {
while (at(SEMICOLON)) advance(); // SEMICOLON while (at(SEMICOLON)) advance(); // SEMICOLON
while (!eof() && !at(RBRACE)) { while (!eof() && !at(RBRACE)) {
if (!atSet(STATEMENT_FIRST)) { if (!atSet(STATEMENT_FIRST)) {
errorAndAdvance("Expecting an element"); errorAndAdvance("Expecting an element");
} }
if (atSet(STATEMENT_FIRST)) { if (atSet(STATEMENT_FIRST)) {
parseStatement(); parseStatement(isScriptTopLevel);
} }
if (at(SEMICOLON)) { if (at(SEMICOLON)) {
while (at(SEMICOLON)) advance(); // SEMICOLON while (at(SEMICOLON)) advance(); // SEMICOLON
@@ -1214,11 +1222,16 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
* : declaration * : declaration
* ; * ;
*/ */
private void parseStatement() { private void parseStatement(boolean isScriptTopLevel) {
if (!parseLocalDeclaration()) { if (!parseLocalDeclaration()) {
if (!atSet(EXPRESSION_FIRST)) { if (!atSet(EXPRESSION_FIRST)) {
errorAndAdvance("Expecting a statement"); errorAndAdvance("Expecting a statement");
} }
else if (isScriptTopLevel){
PsiBuilder.Marker scriptInitializer = mark();
parseExpression();
scriptInitializer.done(ANONYMOUS_INITIALIZER);
}
else { else {
parseExpression(); parseExpression();
} }
@@ -160,7 +160,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
PsiBuilder.Marker blockMarker = mark(); PsiBuilder.Marker blockMarker = mark();
myExpressionParsing.parseStatements(); myExpressionParsing.parseStatements(/*isScriptTopLevel = */true);
checkForUnexpectedSymbols(); checkForUnexpectedSymbols();
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.psi;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.lexer.KtTokens;
@@ -59,4 +60,15 @@ public class KtClassInitializer extends KtDeclarationStub<KotlinPlaceHolderStub<
public PsiElement getInitKeyword() { public PsiElement getInitKeyword() {
return findChildByType(KtTokens.INIT_KEYWORD); return findChildByType(KtTokens.INIT_KEYWORD);
} }
@NotNull
public KtDeclaration getContainingDeclaration() {
KtClassOrObject classOrObject = PsiTreeUtil.getParentOfType(this, KtClassOrObject.class, true);
if (classOrObject != null) {
return classOrObject;
}
KtScript type = PsiTreeUtil.getParentOfType(this, KtScript.class, true);
assert type != null : "Should only be present in class, object or script";
return type;
}
} }
+69 -67
View File
@@ -58,71 +58,73 @@ JetFile: ComplexScript.kts
PsiWhiteSpace('\n') PsiWhiteSpace('\n')
PsiElement(RBRACE)('}') PsiElement(RBRACE)('}')
PsiWhiteSpace('\n\n') PsiWhiteSpace('\n\n')
IF ANONYMOUS_INITIALIZER
PsiElement(if)('if') IF
PsiWhiteSpace(' ') PsiElement(if)('if')
PsiElement(LPAR)('(') PsiWhiteSpace(' ')
CONDITION PsiElement(LPAR)('(')
BINARY_EXPRESSION CONDITION
DOT_QUALIFIED_EXPRESSION BINARY_EXPRESSION
REFERENCE_EXPRESSION DOT_QUALIFIED_EXPRESSION
PsiElement(IDENTIFIER)('args') REFERENCE_EXPRESSION
PsiElement(DOT)('.') PsiElement(IDENTIFIER)('args')
REFERENCE_EXPRESSION PsiElement(DOT)('.')
PsiElement(IDENTIFIER)('length') REFERENCE_EXPRESSION
PsiWhiteSpace(' ') PsiElement(IDENTIFIER)('length')
OPERATION_REFERENCE PsiWhiteSpace(' ')
PsiElement(EQEQ)('==') OPERATION_REFERENCE
PsiWhiteSpace(' ') PsiElement(EQEQ)('==')
INTEGER_CONSTANT PsiWhiteSpace(' ')
PsiElement(INTEGER_LITERAL)('0') INTEGER_CONSTANT
PsiElement(RPAR)(')') PsiElement(INTEGER_LITERAL)('0')
PsiWhiteSpace(' ') PsiElement(RPAR)(')')
THEN PsiWhiteSpace(' ')
BLOCK THEN
PsiElement(LBRACE)('{') BLOCK
PsiWhiteSpace('\n ') PsiElement(LBRACE)('{')
CALL_EXPRESSION PsiWhiteSpace('\n ')
REFERENCE_EXPRESSION CALL_EXPRESSION
PsiElement(IDENTIFIER)('die') REFERENCE_EXPRESSION
VALUE_ARGUMENT_LIST PsiElement(IDENTIFIER)('die')
PsiElement(LPAR)('(') VALUE_ARGUMENT_LIST
VALUE_ARGUMENT PsiElement(LPAR)('(')
STRING_TEMPLATE VALUE_ARGUMENT
PsiElement(OPEN_QUOTE)('"') STRING_TEMPLATE
LITERAL_STRING_TEMPLATE_ENTRY PsiElement(OPEN_QUOTE)('"')
PsiElement(REGULAR_STRING_PART)('Need arguments') LITERAL_STRING_TEMPLATE_ENTRY
PsiElement(CLOSING_QUOTE)('"') PsiElement(REGULAR_STRING_PART)('Need arguments')
PsiElement(RPAR)(')') PsiElement(CLOSING_QUOTE)('"')
PsiWhiteSpace('\n') PsiElement(RPAR)(')')
PsiElement(RBRACE)('}') PsiWhiteSpace('\n')
PsiElement(RBRACE)('}')
PsiWhiteSpace('\n\n') PsiWhiteSpace('\n\n')
FOR ANONYMOUS_INITIALIZER
PsiElement(for)('for') FOR
PsiWhiteSpace(' ') PsiElement(for)('for')
PsiElement(LPAR)('(') PsiWhiteSpace(' ')
VALUE_PARAMETER PsiElement(LPAR)('(')
PsiElement(IDENTIFIER)('arg') VALUE_PARAMETER
PsiWhiteSpace(' ') PsiElement(IDENTIFIER)('arg')
PsiElement(in)('in') PsiWhiteSpace(' ')
PsiWhiteSpace(' ') PsiElement(in)('in')
LOOP_RANGE PsiWhiteSpace(' ')
REFERENCE_EXPRESSION LOOP_RANGE
PsiElement(IDENTIFIER)('args') REFERENCE_EXPRESSION
PsiElement(RPAR)(')') PsiElement(IDENTIFIER)('args')
PsiWhiteSpace(' ') PsiElement(RPAR)(')')
BODY PsiWhiteSpace(' ')
BLOCK BODY
PsiElement(LBRACE)('{') BLOCK
PsiWhiteSpace('\n ') PsiElement(LBRACE)('{')
CALL_EXPRESSION PsiWhiteSpace('\n ')
REFERENCE_EXPRESSION CALL_EXPRESSION
PsiElement(IDENTIFIER)('println') REFERENCE_EXPRESSION
VALUE_ARGUMENT_LIST PsiElement(IDENTIFIER)('println')
PsiElement(LPAR)('(') VALUE_ARGUMENT_LIST
VALUE_ARGUMENT PsiElement(LPAR)('(')
REFERENCE_EXPRESSION VALUE_ARGUMENT
PsiElement(IDENTIFIER)('arg') REFERENCE_EXPRESSION
PsiElement(RPAR)(')') PsiElement(IDENTIFIER)('arg')
PsiWhiteSpace('\n') PsiElement(RPAR)(')')
PsiElement(RBRACE)('}') PsiWhiteSpace('\n')
PsiElement(RBRACE)('}')
+10 -9
View File
@@ -7,12 +7,13 @@ JetFile: Shebang.kts
PsiWhiteSpace('\n\n') PsiWhiteSpace('\n\n')
SCRIPT SCRIPT
BLOCK BLOCK
CALL_EXPRESSION ANONYMOUS_INITIALIZER
REFERENCE_EXPRESSION CALL_EXPRESSION
PsiElement(IDENTIFIER)('println') REFERENCE_EXPRESSION
VALUE_ARGUMENT_LIST PsiElement(IDENTIFIER)('println')
PsiElement(LPAR)('(') VALUE_ARGUMENT_LIST
VALUE_ARGUMENT PsiElement(LPAR)('(')
REFERENCE_EXPRESSION VALUE_ARGUMENT
PsiElement(IDENTIFIER)('args') REFERENCE_EXPRESSION
PsiElement(RPAR)(')') PsiElement(IDENTIFIER)('args')
PsiElement(RPAR)(')')
+20 -18
View File
@@ -5,30 +5,32 @@ JetFile: ShebangIncorrect.kts
<empty list> <empty list>
SCRIPT SCRIPT
BLOCK BLOCK
CALL_EXPRESSION ANONYMOUS_INITIALIZER
REFERENCE_EXPRESSION CALL_EXPRESSION
PsiElement(IDENTIFIER)('println') REFERENCE_EXPRESSION
VALUE_ARGUMENT_LIST PsiElement(IDENTIFIER)('println')
PsiElement(LPAR)('(') VALUE_ARGUMENT_LIST
VALUE_ARGUMENT PsiElement(LPAR)('(')
INTEGER_CONSTANT VALUE_ARGUMENT
PsiElement(INTEGER_LITERAL)('1') INTEGER_CONSTANT
PsiElement(RPAR)(')') PsiElement(INTEGER_LITERAL)('1')
PsiElement(RPAR)(')')
PsiElement(SEMICOLON)(';') PsiElement(SEMICOLON)(';')
PsiWhiteSpace(' ') PsiWhiteSpace(' ')
PsiErrorElement:Expecting an element PsiErrorElement:Expecting an element
PsiElement(HASH)('#') PsiElement(HASH)('#')
BINARY_EXPRESSION ANONYMOUS_INITIALIZER
PREFIX_EXPRESSION BINARY_EXPRESSION
PREFIX_EXPRESSION
OPERATION_REFERENCE
PsiElement(EXCL)('!')
PsiErrorElement:Expecting an element
PsiElement(DIV)('/')
OPERATION_REFERENCE OPERATION_REFERENCE
PsiElement(EXCL)('!') PsiElement(IDENTIFIER)('usr')
PsiWhiteSpace('\n\n')
PsiErrorElement:Expecting an element PsiErrorElement:Expecting an element
PsiElement(DIV)('/') PsiElement(HASH)('#')
OPERATION_REFERENCE
PsiElement(IDENTIFIER)('usr')
PsiWhiteSpace('\n\n')
PsiErrorElement:Expecting an element
PsiElement(HASH)('#')
PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line)
PsiElement(EXCL)('!') PsiElement(EXCL)('!')
PsiElement(DIV)('/') PsiElement(DIV)('/')
+10 -9
View File
@@ -5,12 +5,13 @@ JetFile: SimpleScript.kts
<empty list> <empty list>
SCRIPT SCRIPT
BLOCK BLOCK
CALL_EXPRESSION ANONYMOUS_INITIALIZER
REFERENCE_EXPRESSION CALL_EXPRESSION
PsiElement(IDENTIFIER)('println') REFERENCE_EXPRESSION
VALUE_ARGUMENT_LIST PsiElement(IDENTIFIER)('println')
PsiElement(LPAR)('(') VALUE_ARGUMENT_LIST
VALUE_ARGUMENT PsiElement(LPAR)('(')
INTEGER_CONSTANT VALUE_ARGUMENT
PsiElement(INTEGER_LITERAL)('1') INTEGER_CONSTANT
PsiElement(RPAR)(')') PsiElement(INTEGER_LITERAL)('1')
PsiElement(RPAR)(')')
+11 -10
View File
@@ -5,15 +5,16 @@ JetFile: unexpectedSymbol.kts
<empty list> <empty list>
SCRIPT SCRIPT
BLOCK BLOCK
CALL_EXPRESSION ANONYMOUS_INITIALIZER
REFERENCE_EXPRESSION CALL_EXPRESSION
PsiElement(IDENTIFIER)('println') REFERENCE_EXPRESSION
VALUE_ARGUMENT_LIST PsiElement(IDENTIFIER)('println')
PsiElement(LPAR)('(') VALUE_ARGUMENT_LIST
VALUE_ARGUMENT PsiElement(LPAR)('(')
INTEGER_CONSTANT VALUE_ARGUMENT
PsiElement(INTEGER_LITERAL)('1') INTEGER_CONSTANT
PsiElement(RPAR)(')') PsiElement(INTEGER_LITERAL)('1')
PsiElement(RPAR)(')')
PsiWhiteSpace('\n') PsiWhiteSpace('\n')
PsiErrorElement:unexpected symbol PsiErrorElement:unexpected symbol
PsiElement(RBRACE)('}') PsiElement(RBRACE)('}')
@@ -41,6 +41,12 @@ public abstract class AbstractParsingTest extends ParsingTestCase {
System.setProperty("idea.platform.prefix", "Idea"); System.setProperty("idea.platform.prefix", "Idea");
} }
@Override
protected void setUp() throws Exception {
super.setUp();
getProject().registerService(KotlinScriptDefinitionProvider.class);
}
@Override @Override
protected String getTestDataPath() { protected String getTestDataPath() {
return KotlinTestUtils.getHomeDirectory(); return KotlinTestUtils.getHomeDirectory();