diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index bb544d96640..9b562d8ca11 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -294,14 +294,6 @@
-
-
-
-
-
-
-
-
@@ -317,17 +309,7 @@
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 0f7b991f158..7972e03de17 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,6 +3,9 @@
+
+
+
diff --git a/grammar/src/expressions.grm b/grammar/src/expressions.grm
index d51a859b5c2..f1c55a4dd29 100644
--- a/grammar/src/expressions.grm
+++ b/grammar/src/expressions.grm
@@ -3,7 +3,6 @@ expression
: literalConstant
: functionLiteral
: tupleLiteral
- : "null"
: "this" ("<" type ">")?
: expressionWithPrecedences
: match
@@ -25,6 +24,7 @@ literalConstant
: IntegerLiteral
: HexadecimalLiteral
: CharacterLiteral
+ : "null"
;
declaration
@@ -83,14 +83,14 @@ binaryOperation // Decreasing precedence
: ".."
: SimpleName
: "?:"
- : "in" : "is" : "!in" : "!is" : "as"
+ : "in" : "is" : "!in" : "!is" : "as" : ":"
: "<" : ">" : ">=" : "<="
: "!=" : "==" : "===" : "!=="
// No | & ^ ~
: "&&"
: "||"
+ : "match"
: "->"
- : ":"
: assignmentOperator
;
diff --git a/grammar/src/match.grm b/grammar/src/match.grm
index 0f73398fcba..d18d5067511 100644
--- a/grammar/src/match.grm
+++ b/grammar/src/match.grm
@@ -12,6 +12,7 @@ pattern
: tuplePattern
: bindingPattern // we allow non-linear patterns
: decomposerPattern // labeled components are allowed
+ : arrowPattern
;
constantPattern
@@ -29,4 +30,8 @@ bindingPattern
decomposerPattern
: userType tuplePattern?
+ ;
+
+arrowPattern
+ : pattern "->" pattern
;
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/jet/lang/parsing/AbstractJetParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/AbstractJetParsing.java
index 045c5d59457..130e53b4bd7 100644
--- a/idea/src/org/jetbrains/jet/lang/parsing/AbstractJetParsing.java
+++ b/idea/src/org/jetbrains/jet/lang/parsing/AbstractJetParsing.java
@@ -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;
diff --git a/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java
index c70377b830f..4f872c13af8 100644
--- a/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java
+++ b/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java
@@ -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 ")"
diff --git a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java
index ad4bcf573b3..0cc0874ecff 100644
--- a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java
+++ b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java
@@ -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 tokenConsumer) {
+ public void parseModifierList(Consumer 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 {
+ /*package*/ static class EnumDetector implements Consumer {
private boolean myEnum = false;
diff --git a/idea/testData/psi/LocalDeclarations.jet b/idea/testData/psi/LocalDeclarations.jet
new file mode 100644
index 00000000000..5365c22249b
--- /dev/null
+++ b/idea/testData/psi/LocalDeclarations.jet
@@ -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)
+}
diff --git a/idea/testData/psi/LocalDeclarations.txt b/idea/testData/psi/LocalDeclarations.txt
new file mode 100644
index 00000000000..ad6f707045a
--- /dev/null
+++ b/idea/testData/psi/LocalDeclarations.txt
@@ -0,0 +1,158 @@
+JetFile: LocalDeclarations.jet
+ NAMESPACE
+ FUN
+ PsiElement(fun)('fun')
+ PsiWhiteSpace(' ')
+ PsiElement(IDENTIFIER)('foo')
+ TYPE_PARAMETER_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
+
+ 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
+
+ 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
+
+ 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
+
+ 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)('}')
\ No newline at end of file
diff --git a/idea/testData/psi/LocalDeclarations_ERR.jet b/idea/testData/psi/LocalDeclarations_ERR.jet
new file mode 100644
index 00000000000..b45037565fb
--- /dev/null
+++ b/idea/testData/psi/LocalDeclarations_ERR.jet
@@ -0,0 +1,5 @@
+fun foo() {
+ [a]
+ 1
+ [a]
+}
diff --git a/idea/testData/psi/LocalDeclarations_ERR.txt b/idea/testData/psi/LocalDeclarations_ERR.txt
new file mode 100644
index 00000000000..3d77fe5c4da
--- /dev/null
+++ b/idea/testData/psi/LocalDeclarations_ERR.txt
@@ -0,0 +1,35 @@
+JetFile: LocalDeclarations_ERR.jet
+ NAMESPACE
+ FUN
+ PsiElement(fun)('fun')
+ PsiWhiteSpace(' ')
+ PsiElement(IDENTIFIER)('foo')
+ TYPE_PARAMETER_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)('}')
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/jet/parsing/JetParsingTest.java b/idea/tests/org/jetbrains/jet/parsing/JetParsingTest.java
index cea09fb07c4..0ba579a233d 100644
--- a/idea/tests/org/jetbrains/jet/parsing/JetParsingTest.java
+++ b/idea/tests/org/jetbrains/jet/parsing/JetParsingTest.java
@@ -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);}