diff --git a/grammar/src/class_members.grm b/grammar/src/class_members.grm
index 538d1767f30..576c0fd0e8b 100644
--- a/grammar/src/class_members.grm
+++ b/grammar/src/class_members.grm
@@ -63,7 +63,7 @@ initializer
;
block
- : "{" expressions "}"
+ : "{" statements "}"
;
function
diff --git a/grammar/src/expressions.grm b/grammar/src/expressions.grm
index 78021744d51..f77625fb414 100644
--- a/grammar/src/expressions.grm
+++ b/grammar/src/expressions.grm
@@ -89,7 +89,7 @@ atomicExpression
: "typeof" "(" expression ")"
: "new" constructorInvocation
: objectLiteral
- : declaration
+// : declaration
: jump
: loop
: SimpleName
@@ -126,6 +126,11 @@ declaration
: typedef
;
+statement
+ : declaration
+ : expression
+ ;
+
multiplicativeOperation
: "*" : "/" : "%"
;
@@ -215,13 +220,13 @@ tupleLiteral // Ambiguity when after a SimpleName (infix call). In this case (e)
;
functionLiteral // one can use "it" as a parameter name
- : "{" expressions "}"
- : "{" (type ".")? modifiers SimpleName "=>" expressions "}"
- : "{" (type ".")? "(" (modifiers SimpleName (":" type)?){","} ")" (":" type)? "=>" expressions "}"
+ : "{" statements "}"
+ : "{" (type ".")? modifiers SimpleName "=>" statements "}"
+ : "{" (type ".")? "(" (modifiers SimpleName (":" type)?){","} ")" (":" type)? "=>" statements "}"
;
-expressions
- : SEMI* expression{SEMI+} SEMI*
+statements
+ : SEMI* statement{SEMI+} SEMI*
;
constructorInvocation
diff --git a/idea/src/org/jetbrains/jet/lang/parsing/AbstractJetParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/AbstractJetParsing.java
index 3a0b600f394..c9ce19b2867 100644
--- a/idea/src/org/jetbrains/jet/lang/parsing/AbstractJetParsing.java
+++ b/idea/src/org/jetbrains/jet/lang/parsing/AbstractJetParsing.java
@@ -172,11 +172,13 @@ import static org.jetbrains.jet.lexer.JetTokens.*;
myBuilder.remapCurrentToken(keywordToken);
return true;
}
- } else {
+ }
+ else {
// We know at this point that set does not contain token
if (set.contains(IDENTIFIER) && token instanceof JetKeywordToken) {
if (((JetKeywordToken) token).isSoft()) {
myBuilder.remapCurrentToken(IDENTIFIER);
+ return true;
}
}
}
diff --git a/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java
index 3c14d0047f7..2484e5db4d6 100644
--- a/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java
+++ b/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java
@@ -31,7 +31,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
COLON
);
- /*package*/ static final TokenSet EXPRESSION_FIRST = TokenSet.orSet(TokenSet.create(
+ /*package*/ static final TokenSet EXPRESSION_FIRST = TokenSet.create(
// Prefix
MINUS, PLUS, MINUSMINUS, PLUSPLUS, EXCL, LBRACKET, LABEL_IDENTIFIER, AT, ATAT,
// Atomic
@@ -57,14 +57,6 @@ public class JetExpressionParsing extends AbstractJetParsing {
NEW_KEYWORD, // new
OBJECT_KEYWORD, // object
- // declaration
- LBRACKET, // attribute
- FUN_KEYWORD,
- VAL_KEYWORD, VAR_KEYWORD,
- EXTENSION_KEYWORD,
- CLASS_KEYWORD,
- TYPE_KEYWORD,
-
// jump
THROW_KEYWORD,
RETURN_KEYWORD,
@@ -80,7 +72,21 @@ public class JetExpressionParsing extends AbstractJetParsing {
FIELD_IDENTIFIER, // Field reference
NAMESPACE_KEYWORD // for absolute qualified names
- ), MODIFIER_KEYWORDS);
+ );
+
+ private static final TokenSet STATEMENT_FIRST = TokenSet.orSet(
+ EXPRESSION_FIRST,
+ TokenSet.create(
+ // declaration
+ LBRACKET, // attribute
+ FUN_KEYWORD,
+ VAL_KEYWORD, VAR_KEYWORD,
+ EXTENSION_KEYWORD,
+ CLASS_KEYWORD,
+ TYPE_KEYWORD
+ ),
+ MODIFIER_KEYWORDS
+ );
/*package*/ static final TokenSet EXPRESSION_FOLLOW = TokenSet.create(
SEMICOLON, DOUBLE_ARROW, COMMA, RBRACE, RPAR, RBRACKET
@@ -523,13 +529,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
parseSimpleNameExpression();
}
else if (at(IDENTIFIER)) {
- if (JetParsing.MODIFIER_KEYWORD_MAP.containsKey(myBuilder.getTokenText())) {
- if (!parseLocalDeclaration()) {
- parseSimpleNameExpression();
- }
- } else {
- parseSimpleNameExpression();
- }
+ parseSimpleNameExpression();
}
else if (at(LBRACE)) {
parseFunctionLiteral();
@@ -1022,7 +1022,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
}
PsiBuilder.Marker body = mark();
- parseExpressions();
+ parseStatements();
body.done(BODY);
expect(RBRACE, "Expecting '}'");
@@ -1073,27 +1073,39 @@ public class JetExpressionParsing extends AbstractJetParsing {
/*
* expressions
- * : SEMI* element{SEMI+} SEMI*
+ * : SEMI* statement{SEMI+} SEMI*
*/
- public void parseExpressions() {
+ public void parseStatements() {
while (at(SEMICOLON)) advance(); // SEMICOLON
while (!eof() && !at(RBRACE)) {
- if (!atSet(EXPRESSION_FIRST)) {
+ if (!atSet(STATEMENT_FIRST)) {
errorAndAdvance("Expecting an element");
}
- if (atSet(EXPRESSION_FIRST)) {
- parseExpression();
+ if (atSet(STATEMENT_FIRST)) {
+ parseStatement();
}
if (at(SEMICOLON)) {
while (at(SEMICOLON)) advance(); // SEMICOLON
} else if (at(RBRACE)) {
break;
} else if (!myBuilder.newlineBeforeCurrentToken()) {
- errorUntil("Unexpected tokens (use ';' to separate expressions on the same line", TokenSet.create(EOL_OR_SEMICOLON));
+ errorUntil("Unexpected tokens (use ';' to separate expressions on the same line)", TokenSet.create(EOL_OR_SEMICOLON));
}
}
}
+ /*
+ * statement
+ * : expression
+ * : declaration
+ * ;
+ */
+ private void parseStatement() {
+ if (!parseLocalDeclaration()) {
+ parseExpression();
+ }
+ }
+
/*
* declaration
* : function
diff --git a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java
index 0ccc475b30d..2f6cd5b0f22 100644
--- a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java
+++ b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java
@@ -921,7 +921,7 @@ public class JetParsing extends AbstractJetParsing {
myBuilder.enableNewlines();
expect(LBRACE, "Expecting '{' to open a block");
- myExpressionParsing.parseExpressions();
+ myExpressionParsing.parseStatements();
expect(RBRACE, "Expecting '}");
myBuilder.restoreNewlinesState();
diff --git a/idea/testData/psi/ModifierAsSelector.jet b/idea/testData/psi/ModifierAsSelector.jet
new file mode 100644
index 00000000000..137426ea38b
--- /dev/null
+++ b/idea/testData/psi/ModifierAsSelector.jet
@@ -0,0 +1,5 @@
+// JET-1
+
+val z = System.out
+
+fun foo() { throw new Exception(); }
diff --git a/idea/testData/psi/ModifierAsSelector.txt b/idea/testData/psi/ModifierAsSelector.txt
new file mode 100644
index 00000000000..ac832441ecf
--- /dev/null
+++ b/idea/testData/psi/ModifierAsSelector.txt
@@ -0,0 +1,47 @@
+JetFile: ModifierAsSelector.jet
+ PsiComment(EOL_COMMENT)('// JET-1')
+ PsiWhiteSpace('\n\n')
+ NAMESPACE
+ PROPERTY
+ PsiElement(val)('val')
+ PsiWhiteSpace(' ')
+ PsiElement(IDENTIFIER)('z')
+ PsiWhiteSpace(' ')
+ PsiElement(EQ)('=')
+ PsiWhiteSpace(' ')
+ DOT_QUALIFIED_EXPRESSION
+ REFERENCE_EXPRESSION
+ PsiElement(IDENTIFIER)('System')
+ PsiElement(DOT)('.')
+ REFERENCE_EXPRESSION
+ PsiElement(IDENTIFIER)('out')
+ PsiWhiteSpace('\n\n')
+ FUN
+ PsiElement(fun)('fun')
+ PsiWhiteSpace(' ')
+ PsiElement(IDENTIFIER)('foo')
+ TYPE_PARAMETER_LIST
+
+ VALUE_PARAMETER_LIST
+ PsiElement(LPAR)('(')
+ PsiElement(RPAR)(')')
+ PsiWhiteSpace(' ')
+ BLOCK
+ PsiElement(LBRACE)('{')
+ PsiWhiteSpace(' ')
+ THROW
+ PsiElement(throw)('throw')
+ PsiWhiteSpace(' ')
+ NEW
+ PsiElement(new)('new')
+ PsiWhiteSpace(' ')
+ TYPE_REFERENCE
+ USER_TYPE
+ REFERENCE_EXPRESSION
+ PsiElement(IDENTIFIER)('Exception')
+ VALUE_ARGUMENT_LIST
+ PsiElement(LPAR)('(')
+ PsiElement(RPAR)(')')
+ PsiElement(SEMICOLON)(';')
+ PsiWhiteSpace(' ')
+ PsiElement(RBRACE)('}')
\ No newline at end of file