[groovy] 'for': parse expression list in update (IDEA-188433)

This commit is contained in:
Daniil Ovchinnikov
2018-07-02 16:19:00 +03:00
parent ffdf8be1da
commit e278d4d70e
9 changed files with 105 additions and 8 deletions
@@ -141,6 +141,9 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser {
else if (t == EXPRESSION) {
r = expression(b, 0, -1);
}
else if (t == EXPRESSION_LIST) {
r = expression_list(b, 0);
}
else if (t == FIELD) {
r = field(b, 0);
}
@@ -3161,6 +3164,40 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser {
return r;
}
/* ********************************************************** */
// expression (',' expression)*
public static boolean expression_list(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "expression_list")) return false;
boolean r;
Marker m = enter_section_(b, l, _NONE_, EXPRESSION_LIST, "<expression list>");
r = expression(b, l + 1, -1);
r = r && expression_list_1(b, l + 1);
exit_section_(b, l, m, r, false, null);
return r;
}
// (',' expression)*
private static boolean expression_list_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "expression_list_1")) return false;
while (true) {
int c = current_position_(b);
if (!expression_list_1_0(b, l + 1)) break;
if (!empty_element_parsed_guard_(b, "expression_list_1", c)) break;
}
return true;
}
// ',' expression
private static boolean expression_list_1_0(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "expression_list_1_0")) return false;
boolean r;
Marker m = enter_section_(b);
r = consumeToken(b, T_COMMA);
r = r && expression(b, l + 1, -1);
exit_section_(b, m, null, r);
return r;
}
/* ********************************************************** */
// <<notApplicationArguments expression_or_application_inner>>
public static boolean expression_or_application(PsiBuilder b, int l) {
@@ -3462,6 +3499,12 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser {
return r;
}
/* ********************************************************** */
// expression_list
static boolean for_clause_update(PsiBuilder b, int l) {
return expression_list(b, l + 1);
}
/* ********************************************************** */
// '(' mb_nl for_clause mb_nl ')'
static boolean for_header(PsiBuilder b, int l) {
@@ -6044,7 +6087,7 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
// empty for_clause_initialization? ';' expression? ';' mb_nl expression?
// empty for_clause_initialization? ';' expression? ';' mb_nl for_clause_update?
public static boolean traditional_for_clause(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "traditional_for_clause")) return false;
boolean r, p;
@@ -6075,10 +6118,10 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser {
return true;
}
// expression?
// for_clause_update?
private static boolean traditional_for_clause_6(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "traditional_for_clause_6")) return false;
expression(b, l + 1, -1);
for_clause_update(b, l + 1);
return true;
}
@@ -90,6 +90,7 @@ public interface GroovyElementTypes {
GrEnumDefinitionElementType ENUM_TYPE_DEFINITION = new GrEnumDefinitionElementType("ENUM_TYPE_DEFINITION");
GroovyElementType EQUALITY_EXPRESSION = new GroovyElementType("EQUALITY_EXPRESSION");
GroovyElementType EXPRESSION = new GroovyElementType("EXPRESSION");
GroovyElementType EXPRESSION_LIST = new GroovyElementType("EXPRESSION_LIST");
GrExtendsClauseElementType EXTENDS_CLAUSE = new GrExtendsClauseElementType("EXTENDS_CLAUSE");
GrFieldElementType FIELD = new GrFieldElementType("FIELD");
GroovyElementType FINALLY_CLAUSE = new GroovyElementType("FINALLY_CLAUSE");
@@ -97,6 +97,7 @@ public class GroovyPsiCreator {
if (elem == FOR_STATEMENT) return new GrForStatementImpl(node);
if (elem == FOR_IN_CLAUSE) return new GrForInClauseImpl(node);
if (elem == TRADITIONAL_FOR_CLAUSE) return new GrTraditionalForClauseImpl(node);
if (elem == EXPRESSION_LIST) return new GrExpressionListImpl(node);
if (elem == WHILE_STATEMENT) return new GrWhileStatementImpl(node);
if (elem == DO_WHILE_STATEMENT) return new GrDoWhileStatementImpl(node);
if (elem == TRY_STATEMENT) return new GrTryCatchStatementImpl(node);
@@ -746,11 +746,15 @@ private for_clause ::= for_in_clause | traditional_for_clause
for_in_clause ::= for_in_parameter (':' | 'in') expression { consumeTokenMethod = 'consumeTokenFast' }
for_in_parameter ::= modifier_list mb_type_element IDENTIFIER | clear_variants_and_fail { elementType = parameter }
traditional_for_clause ::= empty for_clause_initialization? ';' expression? ';' mb_nl expression? { pin = 1 }
traditional_for_clause ::= empty for_clause_initialization? ';' expression? ';' mb_nl for_clause_update? { pin = 1 }
private for_clause_initialization ::= traditional_for_parameter | expression | clear_variants_and_fail
traditional_for_parameter ::= traditional_for_parameter_inner mb_initializer { elementType = parameter }
private traditional_for_parameter_inner ::= non_empty_modifier_list mb_type_element IDENTIFIER
| empty_modifier_list type_element IDENTIFIER
private for_clause_update ::= expression_list
expression_list ::= expression (',' expression)*
// FIXME get rid of this weird logic
private for_body ::= &<<extendedStatement>> | &';' | block_or_statement { name = 'loop body' }
@@ -0,0 +1,7 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.groovy.lang.psi.api;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
public interface GrExpressionList extends GroovyPsiElement {
}
@@ -0,0 +1,10 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.groovy.lang.psi.impl
import com.intellij.lang.ASTNode
import org.jetbrains.plugins.groovy.lang.psi.api.GrExpressionList
class GrExpressionListImpl(node: ASTNode) : GroovyPsiElementImpl(node), GrExpressionList {
override fun toString(): String = "Expression list"
}
@@ -121,6 +121,8 @@ class StatementsParsingTest extends GroovyParsingTestCase {
void testFor$for9() throws Throwable { doTest() }
void testFor$for14() throws Throwable { doTest() }
void testFor$idenfierAfterLParen() { doTest() }
void testFor$keywordOnly() { doTest() }
@@ -0,0 +1,28 @@
for (;; 1, 2, 3) {}
-----
Groovy script
For statement
PsiElement(for)('for')
PsiWhiteSpace(' ')
PsiElement(()('(')
Traditional FOR clause
PsiElement(;)(';')
PsiElement(;)(';')
PsiWhiteSpace(' ')
Expression list
Literal
PsiElement(Integer)('1')
PsiElement(,)(',')
PsiWhiteSpace(' ')
Literal
PsiElement(Integer)('2')
PsiElement(,)(',')
PsiWhiteSpace(' ')
Literal
PsiElement(Integer)('3')
PsiElement())(')')
PsiWhiteSpace(' ')
Block statement
Open block
PsiElement({)('{')
PsiElement(})('}')
@@ -26,10 +26,11 @@ Groovy script
PsiElement(Integer)('5')
PsiElement(;)(';')
PsiWhiteSpace(' ')
Unary expression
Reference expression
PsiElement(identifier)('i')
PsiElement(++)('++')
Expression list
Unary expression
Reference expression
PsiElement(identifier)('i')
PsiElement(++)('++')
PsiElement())(')')
Block statement
Open block