Properties. Recovery needs to be fixed
This commit is contained in:
@@ -67,7 +67,7 @@ initializers
|
|||||||
;
|
;
|
||||||
|
|
||||||
block
|
block
|
||||||
: "{" expression "}"
|
: "{" (expression ";"?)* "}"
|
||||||
;
|
;
|
||||||
|
|
||||||
decomposer // TODO: consider other names
|
decomposer // TODO: consider other names
|
||||||
@@ -75,11 +75,7 @@ decomposer // TODO: consider other names
|
|||||||
;
|
;
|
||||||
|
|
||||||
function
|
function
|
||||||
: modifiers "fun" (type ".")? functionRest
|
: modifiers "fun" (type ".")? attributes/*for receiver type*/ typeParameters? functionParameters (":" type)? functionBody?
|
||||||
;
|
|
||||||
|
|
||||||
functionRest
|
|
||||||
: attributes SimpleName typeParameters? functionParameters (":" type)? functionBody?
|
|
||||||
;
|
;
|
||||||
|
|
||||||
functionBody
|
functionBody
|
||||||
@@ -88,12 +84,8 @@ functionBody
|
|||||||
;
|
;
|
||||||
|
|
||||||
property
|
property
|
||||||
: modifiers ("val" | "var") (type ".")? propertyRest
|
: modifiers ("val" | "var") attributes (type ".")? SimpleName (":" type)? ("=" expression)?
|
||||||
;
|
"{" getter? setter? "}"
|
||||||
|
|
||||||
propertyRest
|
|
||||||
: SimpleName (":" type)? ("=" expression)?
|
|
||||||
"{" getter? setter? "}"
|
|
||||||
;
|
;
|
||||||
|
|
||||||
getter
|
getter
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ public interface JetNodeTypes {
|
|||||||
JetNodeType VALUE_PARAMETER = new JetNodeType("VALUE_PARAMETER");
|
JetNodeType VALUE_PARAMETER = new JetNodeType("VALUE_PARAMETER");
|
||||||
JetNodeType FUNCTION_TYPE = new JetNodeType("FUNCTION_TYPE");
|
JetNodeType FUNCTION_TYPE = new JetNodeType("FUNCTION_TYPE");
|
||||||
JetNodeType DECOMPOSER_PROPERTY_LIST = new JetNodeType("DECOMPOSER_PROPERTY_LIST");
|
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");
|
IElementType NAMESPACE_NAME = new JetNodeType("NAMESPACE_NAME");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.jetbrains.jet.lang.parsing;
|
package org.jetbrains.jet.lang.parsing;
|
||||||
|
|
||||||
import com.intellij.lang.PsiBuilder;
|
import com.intellij.lang.PsiBuilder;
|
||||||
|
import com.intellij.psi.TokenType;
|
||||||
import com.intellij.psi.tree.IElementType;
|
import com.intellij.psi.tree.IElementType;
|
||||||
import com.intellij.psi.tree.TokenSet;
|
import com.intellij.psi.tree.TokenSet;
|
||||||
import org.jetbrains.jet.lexer.JetKeywordToken;
|
import org.jetbrains.jet.lexer.JetKeywordToken;
|
||||||
@@ -42,7 +43,7 @@ import static org.jetbrains.jet.lexer.JetTokens.*;
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void errorWithRecovery(String message, TokenSet recoverySet) {
|
protected void errorWithRecovery(String message, TokenSet recoverySet) {
|
||||||
JetToken tt = tt();
|
IElementType tt = tt();
|
||||||
if (recoverySet == null || recoverySet.contains(tt)
|
if (recoverySet == null || recoverySet.contains(tt)
|
||||||
|| (recoverySet.contains(EOL_OR_SEMICOLON)
|
|| (recoverySet.contains(EOL_OR_SEMICOLON)
|
||||||
&& (tt == SEMICOLON || myBuilder.eolInLastWhitespace()))) {
|
&& (tt == SEMICOLON || myBuilder.eolInLastWhitespace()))) {
|
||||||
@@ -68,12 +69,15 @@ import static org.jetbrains.jet.lexer.JetTokens.*;
|
|||||||
myBuilder.advanceLexer();
|
myBuilder.advanceLexer();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected JetToken tt() {
|
protected IElementType tt() {
|
||||||
return (JetToken) myBuilder.getTokenType();
|
IElementType tokenType = myBuilder.getTokenType();
|
||||||
|
// TODO: review
|
||||||
|
if (tokenType == TokenType.BAD_CHARACTER) errorAndAdvance("Bad character");
|
||||||
|
return tokenType;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean at(final IElementType expectation) {
|
protected boolean at(final IElementType expectation) {
|
||||||
JetToken token = tt();
|
IElementType token = tt();
|
||||||
if (token == expectation) return true;
|
if (token == expectation) return true;
|
||||||
if (expectation == EOL_OR_SEMICOLON) {
|
if (expectation == EOL_OR_SEMICOLON) {
|
||||||
if (token == SEMICOLON) return true;
|
if (token == SEMICOLON) return true;
|
||||||
@@ -93,7 +97,7 @@ import static org.jetbrains.jet.lexer.JetTokens.*;
|
|||||||
PsiBuilder.Marker tmp = mark();
|
PsiBuilder.Marker tmp = mark();
|
||||||
for (int i = 0; i < k; i++) advance();
|
for (int i = 0; i < k; i++) advance();
|
||||||
|
|
||||||
JetToken tt = tt();
|
IElementType tt = tt();
|
||||||
tmp.rollbackTo();
|
tmp.rollbackTo();
|
||||||
return tt;
|
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();
|
PsiBuilder.Marker decl = mark();
|
||||||
parseModifierList();
|
parseModifierList();
|
||||||
|
|
||||||
JetToken keywordToken = tt();
|
IElementType keywordToken = tt();
|
||||||
JetNodeType declType = null;
|
JetNodeType declType = null;
|
||||||
if (keywordToken == NAMESPACE_KEYWORD) {
|
if (keywordToken == NAMESPACE_KEYWORD) {
|
||||||
declType = parseNamespaceBlock();
|
declType = parseNamespaceBlock();
|
||||||
@@ -471,14 +471,97 @@ public class JetParsing extends AbstractJetParsing {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* property
|
* property
|
||||||
* : modifiers ("val" | "var") (type ".")? propertyRest
|
* : modifiers ("val" | "var") attributes (type ".")? SimpleName (":" type)? ("=" expression)?
|
||||||
|
* ("{" getter? setter? "}")?
|
||||||
* ;
|
* ;
|
||||||
*/
|
*/
|
||||||
private JetNodeType parseProperty() {
|
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;
|
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
|
* function
|
||||||
* : modifiers "fun" (type ".")? functionRest
|
* : modifiers "fun" (type ".")? functionRest
|
||||||
@@ -493,6 +576,43 @@ public class JetParsing extends AbstractJetParsing {
|
|||||||
return FUN;
|
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
|
* extension
|
||||||
* : modifiers "extension" SimpleName? typeParameters? "for" type classBody? // properties cannot be lazy, cannot have backing fields
|
* : 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() {
|
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();
|
PsiBuilder.Marker parameters = mark();
|
||||||
expect(LPAR, "Expecting '(");
|
expect(LPAR, "Expecting '(");
|
||||||
|
|
||||||
if (!at(RPAR)) {
|
if (!at(RPAR)) {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!parseValueParameter()) {
|
if (!parseValueParameter()) {
|
||||||
parseModifierList(); // lazy, out, ref
|
if (isFunctionTypeContents) {
|
||||||
parseTypeRef();
|
parseModifierList(); // lazy, out, ref
|
||||||
|
parseTypeRef();
|
||||||
|
} else {
|
||||||
|
errorAndAdvance("Expecting a parameter declaration");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!at(COMMA)) break;
|
if (!at(COMMA)) break;
|
||||||
advance(); // COMMA
|
advance(); // COMMA
|
||||||
@@ -845,10 +990,6 @@ public class JetParsing extends AbstractJetParsing {
|
|||||||
}
|
}
|
||||||
expect(RPAR, "Expecting ')'");
|
expect(RPAR, "Expecting ')'");
|
||||||
parameters.done(VALUE_PARAMETER_LIST);
|
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 testFunctionTypes_ERR() throws Exception {doTest(true);}
|
||||||
public void testDecomposers() throws Exception {doTest(true);}
|
public void testDecomposers() throws Exception {doTest(true);}
|
||||||
public void testDecomposers_ERR() 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