Properties. Recovery needs to be fixed
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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() {}
|
||||
}
|
||||
@@ -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);}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user