Decomposers

This commit is contained in:
Andrey Breslav
2010-12-16 21:59:48 +03:00
parent ddf0213e44
commit beded22df5
10 changed files with 426 additions and 53 deletions
+1 -1
View File
@@ -71,7 +71,7 @@ block
;
decomposer // TODO: consider other names
: attributes "decomposer" (type ".")? SimpleName "(" (attributes SimpleName){","} ")" // Public properties only
: modifiers "decomposer" (type ".")? SimpleName? "(" (attributes SimpleName){","}? ")" // Public properties only
;
function
@@ -44,6 +44,7 @@ public interface JetNodeTypes {
JetNodeType TUPLE_TYPE = new JetNodeType("TUPLE_TYPE");
JetNodeType VALUE_PARAMETER = new JetNodeType("VALUE_PARAMETER");
JetNodeType FUNCTION_TYPE = new JetNodeType("FUNCTION_TYPE");
JetNodeType DECOMPOSER_PROPERTY_LIST = new JetNodeType("DECOMPOSER_PROPERTY_LIST");
IElementType NAMESPACE_NAME = new JetNodeType("NAMESPACE_NAME");
@@ -9,11 +9,7 @@ import org.jetbrains.jet.lexer.JetToken;
import static org.jetbrains.jet.lexer.JetTokens.*;
/**
* Created by IntelliJ IDEA.
* User: user
* Date: 12/16/10
* Time: 6:34 PM
* To change this template use File | Settings | File Templates.
* @author abreslav
*/
/*package*/ class AbstractJetParsing {
protected final SemanticWitespaceAwarePsiBuilder myBuilder;
@@ -57,10 +53,11 @@ import static org.jetbrains.jet.lexer.JetTokens.*;
}
}
protected void errorAndAdvance(String message) {
protected boolean errorAndAdvance(String message) {
PsiBuilder.Marker err = mark();
advance(); // erroneous token
err.error(message);
return false;
}
protected boolean eof() {
@@ -104,4 +101,11 @@ import static org.jetbrains.jet.lexer.JetTokens.*;
protected void consumeIf(JetToken token) {
if (at(token)) advance(); // token
}
protected void skipUntil(TokenSet tokenSet) {
while (!eof() && !tokenSet.contains(tt())) {
advance();
}
}
}
@@ -1,5 +1,13 @@
package org.jetbrains.jet.lang.parsing;
import com.intellij.lang.PsiBuilder;
import org.jetbrains.jet.JetNodeType;
import static org.jetbrains.jet.JetNodeTypes.NAMED_ARGUMENT;
import static org.jetbrains.jet.JetNodeTypes.VALUE_ARGUMENT;
import static org.jetbrains.jet.JetNodeTypes.VALUE_ARGUMENT_LIST;
import static org.jetbrains.jet.lexer.JetTokens.*;
/**
* @author abreslav
*/
@@ -36,4 +44,47 @@ public class JetExpressionParsing extends AbstractJetParsing {
advance(); // TODO
}
/*
* valueArguments
* : "(" (SimpleName "=")? ("out" | "ref")? expression{","} ")"
* ;
*/
public void parseValueArgumentList() {
assert at(LPAR);
PsiBuilder.Marker list = mark();
advance(); // LPAR
if (!at(RPAR)) {
while (true) {
parseValueArgument();
if (!at(COMMA)) break;
advance(); // COMMA
}
}
expect(RPAR, "Expecting ')'");
list.done(VALUE_ARGUMENT_LIST);
}
/*
* (SimpleName "=")? ("out" | "ref")? expression
*/
private void parseValueArgument() {
PsiBuilder.Marker argument = mark();
JetNodeType type = VALUE_ARGUMENT;
if (at(IDENTIFIER) && lookahead(1) == EQ) {
advance(); // IDENTIFIER
advance(); // EQ
type = NAMED_ARGUMENT;
}
if (at(OUT_KEYWORD) || at(REF_KEYWORD)) advance(); // REF or OUT
parseExpression();
argument.done(type);
}
}
@@ -16,7 +16,13 @@ import java.util.Map;
import static org.jetbrains.jet.JetNodeTypes.*;
import static org.jetbrains.jet.lexer.JetTokens.*;
/**
* @author max
* @author abreslav
*/
public class JetParsing extends AbstractJetParsing {
// TODO: token sets to constants
private static final Map<String, IElementType> MODIFIER_KEYWORD_MAP = new HashMap<String, IElementType>();
static {
for (IElementType softKeyword : MODIFIER_KEYWORDS.getTypes()) {
@@ -200,11 +206,63 @@ public class JetParsing extends AbstractJetParsing {
/*
* decomposer
* : attributes "decomposer" (type ".")? SimpleName "(" (attributes SimpleName){","} ")" // Public properties only
* : modifiers "decomposer" (type ".")? SimpleName? "(" (attributes SimpleName){","}? ")" // Public properties only
* ;
*/
private JetNodeType parseDecomposer() {
// TODO
assert at(DECOMPOSER_KEYWORD);
advance(); // DECOMPOSER_KEYWORD
boolean extenstion;
if (!at(LPAR)) {
extenstion = true;
if (TYPE_REF_FIRST.contains(tt())
&& !(at(IDENTIFIER) && lookahead(1) == LPAR)) {
// TODO: if this type is annotated with an attribute, and it is a single identifier, it is a error (decomposer [a] foo())
parseTypeRef();
// The decomposer name may appear as the last section of the type
if (at(DOT)) {
advance(); // DOT
expect(IDENTIFIER, "Expecting decomposer name", TokenSet.create(LPAR));
}
}
else {
consumeIf(IDENTIFIER);
}
} else {
extenstion = false;
}
PsiBuilder.Marker properties = mark();
expect(LPAR, "Expecting a property list in parentheses '( ... )'");
if (!at(RPAR)) {
while (true) {
parseAttributeList();
if (!expect(IDENTIFIER, "Expecting a property name", TokenSet.create(COMMA, RPAR))) {
skipUntil(TokenSet.create(COMMA, RPAR, EOL_OR_SEMICOLON));
}
if (!at(COMMA)) {
if (at(RPAR) || at(EOL_OR_SEMICOLON)) break;
error("Expecting a property name or a closing ')'");
skipUntil(TokenSet.create(COMMA, RPAR, EOL_OR_SEMICOLON));
}
if (!at(COMMA)) break;
advance(); // COMMA
}
}
expect(RPAR, "Expecting ')' to close a property list");
consumeIf(SEMICOLON);
properties.done(DECOMPOSER_PROPERTY_LIST);
if (at(DOT) && !extenstion) {
error("Cannot define an extension decomposer on a tuple");
}
return DECOMPOSER;
}
@@ -295,51 +353,10 @@ public class JetParsing extends AbstractJetParsing {
private void parseAttribute() {
PsiBuilder.Marker attribute = mark();
parseUserType();
if (at(LPAR)) parseValueArgumentList();
if (at(LPAR)) myExpressionParsing.parseValueArgumentList();
attribute.done(ATTRIBUTE);
}
/*
* valueArguments
* : "(" (SimpleName "=")? ("out" | "ref")? expression{","} ")"
* ;
*/
private void parseValueArgumentList() {
assert at(LPAR);
PsiBuilder.Marker list = mark();
advance(); // LPAR
if (!at(RPAR)) {
while (true) {
parseValueArgument();
if (!at(COMMA)) break;
advance(); // COMMA
}
}
expect(RPAR, "Expecting ')'");
list.done(VALUE_ARGUMENT_LIST);
}
/*
* (SimpleName "=")? ("out" | "ref")? expression
*/
private void parseValueArgument() {
PsiBuilder.Marker argument = mark();
JetNodeType type = VALUE_ARGUMENT;
if (at(IDENTIFIER) && lookahead(1) == EQ) {
advance(); // IDENTIFIER
advance(); // EQ
type = NAMED_ARGUMENT;
}
if (at(OUT_KEYWORD) || at(REF_KEYWORD)) advance(); // REF or OUT
myExpressionParsing.parseExpression();
argument.done(type);
}
/*
* namespace
* : "namespace" SimpleName{"."} "{"
@@ -535,7 +552,7 @@ public class JetParsing extends AbstractJetParsing {
delegator.done(DELEGATOR_BY);
}
else if (at(LPAR)) {
parseValueArgumentList();
myExpressionParsing.parseValueArgumentList();
delegator.done(DELEGATOR_SUPER_CALL);
}
else {
@@ -762,7 +779,9 @@ public class JetParsing extends AbstractJetParsing {
if (!at(RPAR)) {
while (true) {
if (at(COLON)) errorAndAdvance("Expecting a name for tuple entry");
if (at(COLON)) {
errorAndAdvance("Expecting a name for tuple entry");
}
if (at(IDENTIFIER) && lookahead(1) == COLON) {
PsiBuilder.Marker labeledEntry = mark();
+6
View File
@@ -0,0 +1,6 @@
decomposer (a, a)
decomposer ()
decomposer foo<T>.{() : ()}.bar(a, a)
decomposer a.foobar()
[a] decomposer foobar([a] s)
decomposer foobar()
+103
View File
@@ -0,0 +1,103 @@
JetFile: Decomposers.jet
NAMESPACE
DECOMPOSER
PsiElement(decomposer)('decomposer')
PsiWhiteSpace(' ')
DECOMPOSER_PROPERTY_LIST
PsiElement(LPAR)('(')
PsiElement(IDENTIFIER)('a')
PsiElement(COMMA)(',')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('a')
PsiElement(RPAR)(')')
PsiWhiteSpace('\n')
DECOMPOSER
PsiElement(decomposer)('decomposer')
PsiWhiteSpace(' ')
DECOMPOSER_PROPERTY_LIST
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
PsiWhiteSpace('\n')
DECOMPOSER
PsiElement(decomposer)('decomposer')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
PsiElement(IDENTIFIER)('foo')
TYPE_ARGUMENT_LIST
PsiElement(LT)('<')
TYPE_REFERENCE
USER_TYPE
PsiElement(IDENTIFIER)('T')
PsiElement(GT)('>')
PsiElement(DOT)('.')
FUNCTION_TYPE
PsiElement(LBRACE)('{')
VALUE_PARAMETER_LIST
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
TUPLE_TYPE
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
PsiElement(RBRACE)('}')
PsiElement(DOT)('.')
USER_TYPE
PsiElement(IDENTIFIER)('bar')
DECOMPOSER_PROPERTY_LIST
PsiElement(LPAR)('(')
PsiElement(IDENTIFIER)('a')
PsiElement(COMMA)(',')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('a')
PsiElement(RPAR)(')')
PsiWhiteSpace('\n')
DECOMPOSER
PsiElement(decomposer)('decomposer')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
PsiElement(IDENTIFIER)('a')
PsiElement(DOT)('.')
USER_TYPE
PsiElement(IDENTIFIER)('foobar')
DECOMPOSER_PROPERTY_LIST
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
PsiWhiteSpace('\n')
DECOMPOSER
MODIFIER_LIST
ATTRIBUTE_ANNOTATION
PsiElement(LBRACKET)('[')
ATTRIBUTE
USER_TYPE
USER_TYPE
PsiElement(IDENTIFIER)('a')
PsiElement(RBRACKET)(']')
PsiWhiteSpace(' ')
PsiElement(decomposer)('decomposer')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('foobar')
DECOMPOSER_PROPERTY_LIST
PsiElement(LPAR)('(')
ATTRIBUTE_ANNOTATION
PsiElement(LBRACKET)('[')
ATTRIBUTE
USER_TYPE
USER_TYPE
PsiElement(IDENTIFIER)('a')
PsiElement(RBRACKET)(']')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('s')
PsiElement(RPAR)(')')
PsiWhiteSpace('\n')
DECOMPOSER
PsiElement(decomposer)('decomposer')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('foobar')
DECOMPOSER_PROPERTY_LIST
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
+10
View File
@@ -0,0 +1,10 @@
decomposer (a a)
decomposer foo<T>.{() : ()}.bar(, a)
decomposer a.foobar)
[a] decomposer foobar([a] s, )
decomposer foobar([a])
decomposer (a, a).
decomposer ().
decomposer foo<T>.{() : ()}.bar(a, a).
+177
View File
@@ -0,0 +1,177 @@
JetFile: Decomposers_ERR.jet
NAMESPACE
DECOMPOSER
PsiElement(decomposer)('decomposer')
PsiWhiteSpace(' ')
DECOMPOSER_PROPERTY_LIST
PsiElement(LPAR)('(')
PsiElement(IDENTIFIER)('a')
PsiErrorElement:Expecting a property name or a closing ')'
<empty list>
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('a')
PsiElement(RPAR)(')')
PsiWhiteSpace('\n')
DECOMPOSER
PsiElement(decomposer)('decomposer')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
PsiElement(IDENTIFIER)('foo')
TYPE_ARGUMENT_LIST
PsiElement(LT)('<')
TYPE_REFERENCE
USER_TYPE
PsiElement(IDENTIFIER)('T')
PsiElement(GT)('>')
PsiElement(DOT)('.')
FUNCTION_TYPE
PsiElement(LBRACE)('{')
VALUE_PARAMETER_LIST
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
TUPLE_TYPE
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
PsiElement(RBRACE)('}')
PsiElement(DOT)('.')
USER_TYPE
PsiElement(IDENTIFIER)('bar')
DECOMPOSER_PROPERTY_LIST
PsiElement(LPAR)('(')
PsiErrorElement:Expecting a property name
<empty list>
PsiElement(COMMA)(',')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('a')
PsiElement(RPAR)(')')
PsiWhiteSpace('\n')
DECOMPOSER
PsiElement(decomposer)('decomposer')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
PsiElement(IDENTIFIER)('a')
PsiElement(DOT)('.')
USER_TYPE
PsiElement(IDENTIFIER)('foobar')
DECOMPOSER_PROPERTY_LIST
PsiErrorElement:Expecting a property list in parentheses '( ... )'
<empty list>
PsiElement(RPAR)(')')
PsiWhiteSpace('\n')
DECOMPOSER
MODIFIER_LIST
ATTRIBUTE_ANNOTATION
PsiElement(LBRACKET)('[')
ATTRIBUTE
USER_TYPE
USER_TYPE
PsiElement(IDENTIFIER)('a')
PsiElement(RBRACKET)(']')
PsiWhiteSpace(' ')
PsiElement(decomposer)('decomposer')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('foobar')
DECOMPOSER_PROPERTY_LIST
PsiElement(LPAR)('(')
ATTRIBUTE_ANNOTATION
PsiElement(LBRACKET)('[')
ATTRIBUTE
USER_TYPE
USER_TYPE
PsiElement(IDENTIFIER)('a')
PsiElement(RBRACKET)(']')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('s')
PsiElement(COMMA)(',')
PsiErrorElement:Expecting a property name
<empty list>
PsiWhiteSpace(' ')
PsiElement(RPAR)(')')
PsiWhiteSpace('\n')
DECOMPOSER
PsiElement(decomposer)('decomposer')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('foobar')
DECOMPOSER_PROPERTY_LIST
PsiElement(LPAR)('(')
ATTRIBUTE_ANNOTATION
PsiElement(LBRACKET)('[')
ATTRIBUTE
USER_TYPE
USER_TYPE
PsiElement(IDENTIFIER)('a')
PsiElement(RBRACKET)(']')
PsiErrorElement:Expecting a property name
<empty list>
PsiElement(RPAR)(')')
PsiWhiteSpace('\n\n\n')
DECOMPOSER
PsiElement(decomposer)('decomposer')
PsiWhiteSpace(' ')
DECOMPOSER_PROPERTY_LIST
PsiElement(LPAR)('(')
PsiElement(IDENTIFIER)('a')
PsiElement(COMMA)(',')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('a')
PsiElement(RPAR)(')')
PsiErrorElement:Cannot define an extension decomposer on a tuple
<empty list>
PsiErrorElement:Expecting namespace or top level declaration
PsiElement(DOT)('.')
PsiWhiteSpace('\n')
DECOMPOSER
PsiElement(decomposer)('decomposer')
PsiWhiteSpace(' ')
DECOMPOSER_PROPERTY_LIST
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
PsiErrorElement:Cannot define an extension decomposer on a tuple
<empty list>
PsiErrorElement:Expecting namespace or top level declaration
PsiElement(DOT)('.')
PsiWhiteSpace('\n')
DECOMPOSER
PsiElement(decomposer)('decomposer')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
PsiElement(IDENTIFIER)('foo')
TYPE_ARGUMENT_LIST
PsiElement(LT)('<')
TYPE_REFERENCE
USER_TYPE
PsiElement(IDENTIFIER)('T')
PsiElement(GT)('>')
PsiElement(DOT)('.')
FUNCTION_TYPE
PsiElement(LBRACE)('{')
VALUE_PARAMETER_LIST
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
TUPLE_TYPE
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
PsiElement(RBRACE)('}')
PsiElement(DOT)('.')
USER_TYPE
PsiElement(IDENTIFIER)('bar')
DECOMPOSER_PROPERTY_LIST
PsiElement(LPAR)('(')
PsiElement(IDENTIFIER)('a')
PsiElement(COMMA)(',')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('a')
PsiElement(RPAR)(')')
PsiErrorElement:Expecting namespace or top level declaration
PsiElement(DOT)('.')
@@ -44,4 +44,6 @@ public class JetParsingTest extends ParsingTestCase {
public void testTupleTypes_ERR() throws Exception {doTest(true);}
public void testFunctionTypes() throws Exception {doTest(true);}
public void testFunctionTypes_ERR() throws Exception {doTest(true);}
public void testDecomposers() throws Exception {doTest(true);}
public void testDecomposers_ERR() throws Exception {doTest(true);}
}