Properties. Recovery needs to be fixed

This commit is contained in:
Andrey Breslav
2010-12-16 23:16:32 +03:00
parent beded22df5
commit 3d21852134
7 changed files with 218 additions and 27 deletions
+4 -12
View File
@@ -67,7 +67,7 @@ initializers
;
block
: "{" expression "}"
: "{" (expression ";"?)* "}"
;
decomposer // TODO: consider other names
@@ -75,11 +75,7 @@ decomposer // TODO: consider other names
;
function
: modifiers "fun" (type ".")? functionRest
;
functionRest
: attributes SimpleName typeParameters? functionParameters (":" type)? functionBody?
: modifiers "fun" (type ".")? attributes/*for receiver type*/ typeParameters? functionParameters (":" type)? functionBody?
;
functionBody
@@ -88,12 +84,8 @@ functionBody
;
property
: modifiers ("val" | "var") (type ".")? propertyRest
;
propertyRest
: SimpleName (":" type)? ("=" expression)?
"{" getter? setter? "}"
: modifiers ("val" | "var") attributes (type ".")? SimpleName (":" type)? ("=" expression)?
"{" getter? setter? "}"
;
getter
+2 -1
View File
@@ -45,7 +45,8 @@ public interface JetNodeTypes {
JetNodeType VALUE_PARAMETER = new JetNodeType("VALUE_PARAMETER");
JetNodeType FUNCTION_TYPE = new JetNodeType("FUNCTION_TYPE");
JetNodeType DECOMPOSER_PROPERTY_LIST = new JetNodeType("DECOMPOSER_PROPERTY_LIST");
JetNodeType RECEIVER_TYPE_ATTRIBUTES = new JetNodeType("RECEIVER_TYPE_ATTRIBUTES");
JetNodeType PROPERTY_GETTER = new JetNodeType("PROPERTY_GETTER");
IElementType NAMESPACE_NAME = new JetNodeType("NAMESPACE_NAME");
}
@@ -1,6 +1,7 @@
package org.jetbrains.jet.lang.parsing;
import com.intellij.lang.PsiBuilder;
import com.intellij.psi.TokenType;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.jet.lexer.JetKeywordToken;
@@ -42,7 +43,7 @@ import static org.jetbrains.jet.lexer.JetTokens.*;
}
protected void errorWithRecovery(String message, TokenSet recoverySet) {
JetToken tt = tt();
IElementType tt = tt();
if (recoverySet == null || recoverySet.contains(tt)
|| (recoverySet.contains(EOL_OR_SEMICOLON)
&& (tt == SEMICOLON || myBuilder.eolInLastWhitespace()))) {
@@ -68,12 +69,15 @@ import static org.jetbrains.jet.lexer.JetTokens.*;
myBuilder.advanceLexer();
}
protected JetToken tt() {
return (JetToken) myBuilder.getTokenType();
protected IElementType tt() {
IElementType tokenType = myBuilder.getTokenType();
// TODO: review
if (tokenType == TokenType.BAD_CHARACTER) errorAndAdvance("Bad character");
return tokenType;
}
protected boolean at(final IElementType expectation) {
JetToken token = tt();
IElementType token = tt();
if (token == expectation) return true;
if (expectation == EOL_OR_SEMICOLON) {
if (token == SEMICOLON) return true;
@@ -93,7 +97,7 @@ import static org.jetbrains.jet.lexer.JetTokens.*;
PsiBuilder.Marker tmp = mark();
for (int i = 0; i < k; i++) advance();
JetToken tt = tt();
IElementType tt = tt();
tmp.rollbackTo();
return tt;
}
@@ -108,4 +112,10 @@ import static org.jetbrains.jet.lexer.JetTokens.*;
}
}
protected void errorUntil(String mesage, TokenSet tokenSet) {
PsiBuilder.Marker error = mark();
skipUntil(tokenSet);
error.error(mesage);
}
}
@@ -171,7 +171,7 @@ public class JetParsing extends AbstractJetParsing {
PsiBuilder.Marker decl = mark();
parseModifierList();
JetToken keywordToken = tt();
IElementType keywordToken = tt();
JetNodeType declType = null;
if (keywordToken == NAMESPACE_KEYWORD) {
declType = parseNamespaceBlock();
@@ -471,14 +471,97 @@ public class JetParsing extends AbstractJetParsing {
/*
* property
* : modifiers ("val" | "var") (type ".")? propertyRest
* : modifiers ("val" | "var") attributes (type ".")? SimpleName (":" type)? ("=" expression)?
* ("{" getter? setter? "}")?
* ;
*/
private JetNodeType parseProperty() {
advance(); // TODO
assert at(VAL_KEYWORD) || at(VAR_KEYWORD);
advance(); // VAL_KEYWORD or VAR_KEYWORD
PsiBuilder.Marker receiverTypeAttributes = mark();
parseAttributeList();
TokenSet propertyNameFollow = TokenSet.create(COLON, EQ, LBRACE, EOL_OR_SEMICOLON);
if (at(IDENTIFIER) && propertyNameFollow.contains(lookahead(1))) {
// val [a] name = foo
receiverTypeAttributes.done(RECEIVER_TYPE_ATTRIBUTES);
advance(); // IDENTIFIER
}
else {
receiverTypeAttributes.rollbackTo();
if (!TYPE_REF_FIRST.contains(tt())) {
errorAndAdvance("Expecting receiver type or property name");
}
else {
// TODO: if this type is annotated with an attribute, and it is a single identifier, it is a error (fun [a] foo())
parseTypeRef();
// The property name may appear as the last section of the type
if (at(DOT)) {
advance(); // DOT
expect(IDENTIFIER, "Expecting property name", propertyNameFollow);
}
}
}
if (at(COLON)) {
advance(); // COLON
parseTypeRef();
}
if (at(EQ)) {
advance(); // EQ
myExpressionParsing.parseExpression();
}
if (!at(EOL_OR_SEMICOLON) && at(LBRACE)) {
advance(); // LBRACE
// TODO: review
// TODO: $field = foo or something like this
parsePropertyGetterOrSetter();
if (!at(RBRACE)) parsePropertyGetterOrSetter();
if (!at(RBRACE)) {
errorUntil("Expecting '}'", TokenSet.create(RBRACE));
}
expect(RBRACE, "Expecting '}'");
}
consumeIf(SEMICOLON);
return PROPERTY;
}
/*
* getter
* : modifiers
* ( "get" "(" ")"
* |
* "set" "(" modifiers parameter ")"
* ) functionBody
* ;
*/
private void parsePropertyGetterOrSetter() {
PsiBuilder.Marker getter = mark();
parseModifierList();
if (!at(GET_KEYWORD) && !at(SET_KEYWORD)) {
errorWithRecovery("Expecting 'get' or 'set'", TokenSet.create(LPAR, RBRACE));
}
else {
advance(); // GET_KEYWORD or SET_KEYWORD
}
parseValueParameterList(false);
parseFunctionBody();
getter.done(PROPERTY_GETTER);
}
/*
* function
* : modifiers "fun" (type ".")? functionRest
@@ -493,6 +576,43 @@ public class JetParsing extends AbstractJetParsing {
return FUN;
}
/*
* functionBody
* : block
* : "=" expression
* ;
*/
private void parseFunctionBody() {
if (at(LBRACE)) {
parseBlock();
}
else if (at(EQ)) {
advance(); // EQ
myExpressionParsing.parseExpression();
}
else {
error("Expecting function body");
}
}
/*
* block
* : "{" (expression ";"?)* "}"
* ;
*/
private void parseBlock() {
assert at(LBRACE);
advance(); // LBRACE
while (!eof() && !at(RBRACE)) {
myExpressionParsing.parseExpression();
consumeIf(SEMICOLON);
}
expect(RBRACE, "Expecting '}");
}
/*
* extension
* : modifiers "extension" SimpleName? typeParameters? "for" type classBody? // properties cannot be lazy, cannot have backing fields
@@ -830,14 +950,39 @@ public class JetParsing extends AbstractJetParsing {
* ;
*/
private void parseFunctionTypeContents() {
parseValueParameterList(true);
expect(COLON, "Expecting ':' followed by a return type", TYPE_REF_FIRST);
parseTypeRef();
}
/*
* functionParameters
* : "(" functionParameter{","}? ")" // default values
* ;
*
* functionParameter
* : modifiers functionParameterRest
* ;
*
* functionParameterRest
* : parameter ("=" expression)?
* ;
*/
private void parseValueParameterList(boolean isFunctionTypeContents) {
PsiBuilder.Marker parameters = mark();
expect(LPAR, "Expecting '(");
if (!at(RPAR)) {
while (true) {
if (!parseValueParameter()) {
parseModifierList(); // lazy, out, ref
parseTypeRef();
if (isFunctionTypeContents) {
parseModifierList(); // lazy, out, ref
parseTypeRef();
} else {
errorAndAdvance("Expecting a parameter declaration");
}
}
if (!at(COMMA)) break;
advance(); // COMMA
@@ -845,10 +990,6 @@ public class JetParsing extends AbstractJetParsing {
}
expect(RPAR, "Expecting ')'");
parameters.done(VALUE_PARAMETER_LIST);
expect(COLON, "Expecting ':' followed by a return type", TYPE_REF_FIRST);
parseTypeRef();
}
/*
+28
View File
@@ -0,0 +1,28 @@
val foo
val [a] foo
val foo.bar
val foo.bar.{() : ()}.foo
val foo : T
val [a] foo = bar
val foo.bar {
get() {}
set() = foo
}
val foo.bar.{() : ()}.foo = foo {
get() {}
set() {}
}
val foo.bar.{() : ()}.foo : bar = foo {
[a] public get() {}
virtual set(a : b) {}
}
val foo.bar.{() : ()}.foo : bar = foo {
virtual set(a : b) {}
}
val foo.bar.{() : ()}.foo : bar = foo {
[a] public get() {}
}
+17
View File
@@ -0,0 +1,17 @@
val foo :
val [a foo = foo
val foo.bar.
val [a] foo : = bar
val foo.bar {
public () {}
() = foo
}
val foo.bar.{() : ()}.foo = foo {
dfget() {}
set) {}
}
val foo.bar.{() : ()}.foo = foo {
get(foo) {}
set() {}
set() {}
}
@@ -46,4 +46,6 @@ public class JetParsingTest extends ParsingTestCase {
public void testFunctionTypes_ERR() throws Exception {doTest(true);}
public void testDecomposers() throws Exception {doTest(true);}
public void testDecomposers_ERR() throws Exception {doTest(true);}
public void testProperties() throws Exception {doTest(true);}
public void testProperties_ERR() throws Exception {doTest(true);}
}