Binary operations implemented. Some bugs are caused by incorrect treatment of semantic EOLs when calling rollbackTo() on a marker

This commit is contained in:
Andrey Breslav
2010-12-29 23:39:23 +03:00
parent b56b4c8930
commit 300af58774
6 changed files with 342 additions and 105 deletions
+108 -56
View File
@@ -1,12 +1,96 @@
/*
Decreasing precedence:
memberAccessOperation
postfixUnaryOperation
prefixUnaryOperation
multiplicativeOperation
additiveOperation
".."
SimpleName
"?:"
namedInfixOrTypeOperation
comparisonOperation
equalityOperation
"&&"
"||"
"match"
"->"
assignmentOperator
*/
expression expression
: attributes expression : arrowTupleExpression (assignmentOperator arrowTupleExpression)?
;
arrowTupleExpression
: match ("->" match)*
;
match
: conjunction ("match" "{" matchEntry+ "}")*
;
disjunction
: conjunction ("||" conjunction)*
;
conjunction
: equalityComparison ("&&" equalityComparison)*
;
equalityComparison
: comparison (equalityOperation comparison)*
;
comparison
: namedInfixOrTypeExpression (comparisonOperation namedInfixOrTypeExpression)*
;
namedInfixOrTypeExpression
: elvisOperation (namedInfixOrTypeOperation elvisOperation)*
;
elvisOperation
: infixFunctionCall ("?:" infixFunctionCall)*
;
infixFunctionCall
: rangeExpression (SimpleName rangeExpression)*
;
rangeExpression
: additiveExpression (".." additiveExpression)*
;
additiveExpression
: multiplicativeExpression (additiveOperation multiplicativeExpression)*
;
multiplicativeExpression
: prefixUnaryExpression (multiplicativeOperation prefixUnaryExpression)*
;
prefixUnaryExpression
: prefixUnaryOperation postfixUnaryExpression
;
postfixUnaryExpression
: memberAccess postfixUnaryOperation
;
memberAccess
: atomicExpression memberAccessOperation atomicExpression
;
atomicExpression
: "(" expression ")" // see tupleLiteral : "(" expression ")" // see tupleLiteral
: literalConstant : literalConstant
: functionLiteral : functionLiteral
: tupleLiteral : tupleLiteral
: "this" ("<" type ">")? : "this" ("<" type ">")?
: expressionWithPrecedences
: match
: if : if
: try : try
: "typeof" "(" expression ")" : "typeof" "(" expression ")"
@@ -15,7 +99,7 @@ expression
: declaration : declaration
: jump : jump
: loop : loop
// block is syntactically equivalent to a functionLiteral with no parameters : SimpleName
; ;
literalConstant literalConstant
@@ -36,63 +120,28 @@ declaration
: typedef : typedef
; ;
expressionWithPrecedences // See the precedence table, everything associates to the left memberAccessOperation
: memberLiteral
: memberAccessExpression
: infixFunctionCall
: binOpExpression
: assignment
: unOpExpression
: castExpression
: typingExpression
;
memberLiteral
: expression? '#' SimpleName
;
memberAccessExpression
: (expression accessOp)? (memberAccess | expression)
;
accessOp
: "."
: "?."
;
typingExpression
: expression typingOperation type
;
typingOperation
: "as"
: "is"
: "isnot"
: ":"
;
binOpExpression
: expression binaryOperation expression // see priorities
;
binaryOperation // Decreasing precedence
: "." : "?." : "#" : "." : "?." : "#"
// unary ;
multiplicativeOperation
: "*" : "/" : "%" : "*" : "/" : "%"
;
additiveOperation
: "+" : "-" : "+" : "-"
// No << >> >>> ;
: ".."
: SimpleName namedInfixOrTypeOperation
: "?:"
: "in" : "is" : "!in" : "!is" : "as" : ":" : "in" : "is" : "!in" : "!is" : "as" : ":"
;
comparisonOperation
: "<" : ">" : ">=" : "<=" : "<" : ">" : ">=" : "<="
;
equalityOperation
: "!=" : "==" : "===" : "!==" : "!=" : "==" : "===" : "!=="
// No | & ^ ~
: "&&"
: "||"
: "match"
: "->"
: assignmentOperator
; ;
assignmentOperator assignmentOperator
@@ -113,10 +162,13 @@ prefixUnaryOperation
: "-" : "+" : "-" : "+"
: "++" : "--" : "++" : "--"
: "!" // No ~ : "!" // No ~
: attributes // mandatory
; ;
postfixUnaryOperation postfixUnaryOperation
: "++" : "--" : "++" : "--"
: valueArguments
: arrayAccess
; ;
functionCall functionCall
@@ -179,7 +231,7 @@ fieldOrPropertyAccess
; ;
arrayAccess arrayAccess
: "[" expression "]" : "[" expression{","} "]"
; ;
objectLiteral objectLiteral
-4
View File
@@ -1,7 +1,3 @@
match
: expression "match" "{" matchEntry+ "}"
;
matchEntry matchEntry
: attributes "case" pattern ("if" "(" expression ")")? "=>" expression // TODO: Consider other options than "=>" : attributes "case" pattern ("if" "(" expression ")")? "=>" expression // TODO: Consider other options than "=>"
; ;
@@ -90,6 +90,13 @@ public interface JetNodeTypes {
JetNodeType RECEIVER_TYPE = new JetNodeType("RECEIVER_TYPE"); JetNodeType RECEIVER_TYPE = new JetNodeType("RECEIVER_TYPE");
JetNodeType FUNCTION_LITERAL = new JetNodeType("FUNCTION_LITERAL"); JetNodeType FUNCTION_LITERAL = new JetNodeType("FUNCTION_LITERAL");
JetNodeType ANNOTATED_EXPRESSION = new JetNodeType("ANNOTATED_EXPRESSION"); JetNodeType ANNOTATED_EXPRESSION = new JetNodeType("ANNOTATED_EXPRESSION");
// JetNodeType SIMPLE_NAME = new JetNodeType("SIMPLE_NAME");
JetNodeType BINARY_EXPRESSION = new JetNodeType("BINARY_EXPRESSION");
JetNodeType PREFIX_EXPRESSION = new JetNodeType("PREFIX_EXPRESSION");
JetNodeType POSTFIX_EXPRESSION = new JetNodeType("POSTFIX_EXPRESSION");
JetNodeType CALL_EXPRESSION = new JetNodeType("CALL_EXPRESSION");
JetNodeType ARRAY_ACCESS_EXPRESSION = new JetNodeType("ARRAY_ACCESS_EXPRESSION");
JetNodeType INDICES = new JetNodeType("INDICES");
IElementType NAMESPACE_NAME = new JetNodeType("NAMESPACE_NAME"); IElementType NAMESPACE_NAME = new JetNodeType("NAMESPACE_NAME");
} }
@@ -4,6 +4,7 @@ import com.intellij.lang.PsiBuilder;
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.JetNodeType; import org.jetbrains.jet.JetNodeType;
import org.jetbrains.jet.lexer.JetTokens;
import static org.jetbrains.jet.JetNodeTypes.*; import static org.jetbrains.jet.JetNodeTypes.*;
import static org.jetbrains.jet.lexer.JetTokens.*; import static org.jetbrains.jet.lexer.JetTokens.*;
@@ -19,6 +20,71 @@ public class JetExpressionParsing extends AbstractJetParsing {
myJetParsing = jetParsing; myJetParsing = jetParsing;
} }
@SuppressWarnings({"UnusedDeclaration"})
private enum Priority {
MEMBER_ACCESS(DOT, HASH, SAFE_ACCESS) {
@Override
public void parseHigherPriority(JetExpressionParsing parsing) {
parsing.parseAtomicExpression();
}
},
POSTFIX(PLUSPLUS, MINUSMINUS), // valueArguments : arrayAccess
PREFIX(MINUS, PLUS, MINUSMINUS, PLUSPLUS, EXCL) { // attributes
@Override
public void parseHigherPriority(JetExpressionParsing parsing) {
throw new IllegalStateException("Don't call this method");
}
},
MULTIPLICATIVE(MUL, DIV, PERC) {
@Override
public void parseHigherPriority(JetExpressionParsing parsing) {
parsing.parsePrefixExpression();
}
},
ADDITIVE(PLUS, MINUS),
RANGE(JetTokens.RANGE),
SIMPLE_NAME(IDENTIFIER),
ELVIS(JetTokens.ELVIS),
NAMED_INFIX_OR_TYPE(IN_KEYWORD, NOT_IN, IS_KEYWORD, NOT_IS, AS_KEYWORD, COLON),
COMPARISON(LT, GT, LTEQ, GTEQ),
EQUALITY(EQEQ, EXCLEQ, EQEQEQ, EXCLEQEQEQ),
CONJUNCTION(ANDAND),
DISJUNCTION(OROR),
MATCH(MATCH_KEYWORD),
ARROW(JetTokens.ARROW),
ASSIGNMENT(EQ, PLUSEQ, MINUSEQ, MULTEQ, DIVEQ, PERCEQ)
;
static {
Priority[] values = Priority.values();
for (Priority priority : values) {
int ordinal = priority.ordinal();
priority.higher = ordinal > 0 ? values[ordinal - 1] : null;
}
}
private Priority higher;
private final TokenSet operations;
Priority(IElementType... operations ) {
this.operations = TokenSet.create(operations);
}
public void parseHigherPriority(JetExpressionParsing parsing) {
assert higher != null;
parsing.parseBinaryExpression(higher);
}
public final TokenSet getOperations() {
return operations;
}
}
/* /*
* expression * expression
* : attributes expression * : attributes expression
@@ -29,7 +95,6 @@ public class JetExpressionParsing extends AbstractJetParsing {
* : "null" * : "null"
* : "this" ("<" type ">")? * : "this" ("<" type ">")?
* : expressionWithPrecedences * : expressionWithPrecedences
* : match
* : if * : if
* : try * : try
* : "typeof" "(" expression ")" * : "typeof" "(" expression ")"
@@ -42,6 +107,86 @@ public class JetExpressionParsing extends AbstractJetParsing {
* ; * ;
*/ */
public void parseExpression() { public void parseExpression() {
parseBinaryExpression(Priority.ASSIGNMENT);
}
private void parseBinaryExpression(Priority priority) {
// System.out.println(priority.name() + " at " + tt());
PsiBuilder.Marker expression = mark();
priority.parseHigherPriority(this);
while (!myBuilder.eolInLastWhitespace() && atSet(priority.getOperations())) {
advance(); // operation
priority.parseHigherPriority(this);
expression.done(BINARY_EXPRESSION);
expression = expression.precede();
}
expression.drop();
}
private void parsePrefixExpression() {
// System.out.println("pre at " + tt());
if (at(LBRACKET)) {
if (!parseLocalDeclaration()) {
PsiBuilder.Marker attributes = mark();
myJetParsing.parseAttributeList();
parsePostfixExpression();
attributes.done(ANNOTATED_EXPRESSION);
}
} else if (atSet(Priority.PREFIX.getOperations())) {
PsiBuilder.Marker expression = mark();
advance(); // operation
parsePostfixExpression();
expression.done(PREFIX_EXPRESSION);
} else {
parsePostfixExpression();
}
}
private void parsePostfixExpression() {
// System.out.println("post at " + tt());
PsiBuilder.Marker expression = mark();
parseBinaryExpression(Priority.MEMBER_ACCESS);
if (myBuilder.eolInLastWhitespace()) {
expression.drop();
} else if (at(LBRACKET)) {
parseArrayAccess();
expression.done(ARRAY_ACCESS_EXPRESSION);
} else if (atSet(Priority.POSTFIX.getOperations())) {
advance(); // operation
expression.done(POSTFIX_EXPRESSION);
} else if (at(LPAR)) {
parseValueArgumentList();
expression.done(CALL_EXPRESSION);
} else {
expression.drop();
}
}
/*
* atomicExpression
* : tupleLiteral // or parenthesized expression
* : "this" ("<" type ">")?
* : "typeof" "(" expression ")"
* : "new" constructorInvocation // TODO: Do we need "new"?, see factory methods
* : objectLiteral
* : jump
* : if
* : try
* : loop
* : literalConstant
* : functionLiteral
* : declaration
* : SimpleName
* ;
*/
private void parseAtomicExpression() {
// System.out.println("atom at " + tt());
if (at(LPAR)) { if (at(LPAR)) {
parseParenthesizedExpressionOrTuple(); parseParenthesizedExpressionOrTuple();
} }
@@ -112,33 +257,61 @@ public class JetExpressionParsing extends AbstractJetParsing {
VAR_KEYWORD, TYPE_KEYWORD, DECOMPOSER_KEYWORD)) { VAR_KEYWORD, TYPE_KEYWORD, DECOMPOSER_KEYWORD)) {
parseLocalDeclaration(); parseLocalDeclaration();
} }
else if (at(LBRACKET)) {
if (!parseLocalDeclaration()) {
PsiBuilder.Marker attributes = mark();
myJetParsing.parseAttributeList();
parseExpression();
attributes.done(ANNOTATED_EXPRESSION);
}
}
else if (at(IDENTIFIER)) { else if (at(IDENTIFIER)) {
if (JetParsing.MODIFIER_KEYWORD_MAP.containsKey(myBuilder.getTokenText())) { if (JetParsing.MODIFIER_KEYWORD_MAP.containsKey(myBuilder.getTokenText())) {
if (!parseLocalDeclaration()) { if (!parseLocalDeclaration()) {
expect(IDENTIFIER, "[Internal error: should never occur]"); parseSimpleName();
// TODO
} }
} else { } else {
expect(IDENTIFIER, "[Internal error: should never occur]"); parseSimpleName();
// TODO
} }
} }
else if (at(LBRACE)) { else if (at(LBRACE)) {
parseFunctionLiteral(); parseFunctionLiteral();
} }
else { else {
// TODO
errorAndAdvance("Expecting an expression"); errorAndAdvance("Expecting an expression");
} }
}
// TODO: Binary operations
/*
* arrayAccess
* : "[" expression{","} "]"
* ;
*/
private void parseArrayAccess() {
assert at(LBRACKET);
PsiBuilder.Marker indices = mark();
advance(); // LBRACKET
while (true) {
if (at(COMMA)) errorAndAdvance("Expecting an index expression");
if (at(RBRACKET)) {
error("Expecting an index expression");
break;
}
parseExpression();
if (!at(COMMA)) break;
advance(); // COMMA
}
expect(RBRACKET, "Expecting ']'");
indices.done(INDICES);
}
/*
* SimpleName
*/
private void parseSimpleName() {
assert at(IDENTIFIER);
// PsiBuilder.Marker simpleName = mark();
advance(); // IDENTIFIER
// simpleName.done(SIMPLE_NAME);
} }
/* /*
@@ -202,36 +375,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
} }
if (at(LPAR)) { if (at(LPAR)) {
PsiBuilder.Marker list = mark(); parseFunctionLiteralParameterList();
expect(LPAR, "Expecting a parameter list in parentheses (...)", TokenSet.create(DOUBLE_ARROW, COLON));
if (!at(RPAR)) {
while (true) {
if (at(COMMA)) errorAndAdvance("Expecting a parameter declaration");
PsiBuilder.Marker parameter = mark();
int parameterNamePos = matchTokenStreamPredicate(new LastBefore(new At(IDENTIFIER), new AtSet(COMMA, RPAR, COLON, DOUBLE_ARROW)));
createTruncatedBuilder(parameterNamePos).parseModifierList();
expect(IDENTIFIER, "Expecting parameter declaration");
if (at(COLON)) {
advance(); // COLON
myJetParsing.parseTypeRef();
}
parameter.done(VALUE_PARAMETER);
if (!at(COMMA)) break;
advance(); // COMMA
if (at(RPAR)) {
error("Expecting a parameter declaration");
break;
}
}
}
expect(RPAR, "Expecting ')", TokenSet.create(DOUBLE_ARROW, COLON));
list.done(VALUE_PARAMETER_LIST);
if (at(COLON)) { if (at(COLON)) {
advance(); // COLON advance(); // COLON
@@ -273,6 +417,42 @@ public class JetExpressionParsing extends AbstractJetParsing {
literal.done(FUNCTION_LITERAL); literal.done(FUNCTION_LITERAL);
} }
/*
* "(" (modifiers SimpleName (":" type)?){","} ")"
*/
private void parseFunctionLiteralParameterList() {
PsiBuilder.Marker list = mark();
expect(LPAR, "Expecting a parameter list in parentheses (...)", TokenSet.create(DOUBLE_ARROW, COLON));
if (!at(RPAR)) {
while (true) {
if (at(COMMA)) errorAndAdvance("Expecting a parameter declaration");
PsiBuilder.Marker parameter = mark();
int parameterNamePos = matchTokenStreamPredicate(new LastBefore(new At(IDENTIFIER), new AtSet(COMMA, RPAR, COLON, DOUBLE_ARROW)));
createTruncatedBuilder(parameterNamePos).parseModifierList();
expect(IDENTIFIER, "Expecting parameter declaration");
if (at(COLON)) {
advance(); // COLON
myJetParsing.parseTypeRef();
}
parameter.done(VALUE_PARAMETER);
if (!at(COMMA)) break;
advance(); // COMMA
if (at(RPAR)) {
error("Expecting a parameter declaration");
break;
}
}
}
expect(RPAR, "Expecting ')", TokenSet.create(DOUBLE_ARROW, COLON));
list.done(VALUE_PARAMETER_LIST);
}
/* /*
* expressions * expressions
* : expression{SEMI} SEMI? * : expression{SEMI} SEMI?
+2 -1
View File
@@ -135,6 +135,7 @@ RAW_STRING_LITERAL = {THREE_QUO} {QUO_STRING_CHAR}* {THREE_QUO}?
<YYINITIAL> "-=" { return JetTokens.MINUSEQ ; } <YYINITIAL> "-=" { return JetTokens.MINUSEQ ; }
<YYINITIAL> "->" { return JetTokens.ARROW ; } <YYINITIAL> "->" { return JetTokens.ARROW ; }
<YYINITIAL> "=>" { return JetTokens.DOUBLE_ARROW; } <YYINITIAL> "=>" { return JetTokens.DOUBLE_ARROW; }
<YYINITIAL> ".." { return JetTokens.RANGE ; }
<YYINITIAL> "[" { return JetTokens.LBRACKET ; } <YYINITIAL> "[" { return JetTokens.LBRACKET ; }
<YYINITIAL> "]" { return JetTokens.RBRACKET ; } <YYINITIAL> "]" { return JetTokens.RBRACKET ; }
<YYINITIAL> "{" { return JetTokens.LBRACE ; } <YYINITIAL> "{" { return JetTokens.LBRACE ; }
@@ -153,9 +154,9 @@ RAW_STRING_LITERAL = {THREE_QUO} {QUO_STRING_CHAR}* {THREE_QUO}?
<YYINITIAL> "?" { return JetTokens.QUEST ; } <YYINITIAL> "?" { return JetTokens.QUEST ; }
<YYINITIAL> ":" { return JetTokens.COLON ; } <YYINITIAL> ":" { return JetTokens.COLON ; }
<YYINITIAL> ";" { return JetTokens.SEMICOLON ; } <YYINITIAL> ";" { return JetTokens.SEMICOLON ; }
<YYINITIAL> ".." { return JetTokens.RANGE ; }
<YYINITIAL> "=" { return JetTokens.EQ ; } <YYINITIAL> "=" { return JetTokens.EQ ; }
<YYINITIAL> "," { return JetTokens.COMMA ; } <YYINITIAL> "," { return JetTokens.COMMA ; }
<YYINITIAL> "#" { return JetTokens.HASH ; }
<YYINITIAL> . { return TokenType.BAD_CHARACTER; } <YYINITIAL> . { return TokenType.BAD_CHARACTER; }
@@ -99,6 +99,7 @@ public interface JetTokens {
JetToken MINUSEQ = new JetToken("MINUSEQ"); JetToken MINUSEQ = new JetToken("MINUSEQ");
JetToken NOT_IN = new JetToken("NOT_IN"); JetToken NOT_IN = new JetToken("NOT_IN");
JetToken NOT_IS = new JetToken("NOT_IS"); JetToken NOT_IS = new JetToken("NOT_IS");
JetToken HASH = new JetToken("HASH");
JetToken COMMA = new JetToken("COMMA"); JetToken COMMA = new JetToken("COMMA");