diff --git a/plugins/groovy/groovy-psi/gen/org/jetbrains/plugins/groovy/lang/parser/GroovyGeneratedParser.java b/plugins/groovy/groovy-psi/gen/org/jetbrains/plugins/groovy/lang/parser/GroovyGeneratedParser.java index 9035b775cdcf..e0fc371055d3 100644 --- a/plugins/groovy/groovy-psi/gen/org/jetbrains/plugins/groovy/lang/parser/GroovyGeneratedParser.java +++ b/plugins/groovy/groovy-psi/gen/org/jetbrains/plugins/groovy/lang/parser/GroovyGeneratedParser.java @@ -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, ""); + 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; + } + /* ********************************************************** */ // <> 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; } diff --git a/plugins/groovy/groovy-psi/gen/org/jetbrains/plugins/groovy/lang/psi/GroovyElementTypes.java b/plugins/groovy/groovy-psi/gen/org/jetbrains/plugins/groovy/lang/psi/GroovyElementTypes.java index 4a10630650e8..3a8b6b011c3a 100644 --- a/plugins/groovy/groovy-psi/gen/org/jetbrains/plugins/groovy/lang/psi/GroovyElementTypes.java +++ b/plugins/groovy/groovy-psi/gen/org/jetbrains/plugins/groovy/lang/psi/GroovyElementTypes.java @@ -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"); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/GroovyPsiCreator.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/GroovyPsiCreator.java index a0d9025cf80b..ae3e302db6a0 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/GroovyPsiCreator.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/GroovyPsiCreator.java @@ -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); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/groovy.bnf b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/groovy.bnf index 99f769b0b28a..a7b3910474d5 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/groovy.bnf +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/groovy.bnf @@ -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 ::= &<> | &';' | block_or_statement { name = 'loop body' } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/GrExpressionList.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/GrExpressionList.java new file mode 100644 index 000000000000..ede7e2d7b82c --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/GrExpressionList.java @@ -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 { +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrExpressionListImpl.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrExpressionListImpl.kt new file mode 100644 index 000000000000..ae0bb4c1a780 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrExpressionListImpl.kt @@ -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" +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/StatementsParsingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/StatementsParsingTest.groovy index e55eaed14e2e..737b3b88eaca 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/StatementsParsingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/StatementsParsingTest.groovy @@ -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() } diff --git a/plugins/groovy/testdata/parsing/groovy/statements/for/for14.test b/plugins/groovy/testdata/parsing/groovy/statements/for/for14.test new file mode 100644 index 000000000000..8c0502e48ab5 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/statements/for/for14.test @@ -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(})('}') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/statements/for/for6.test b/plugins/groovy/testdata/parsing/groovy/statements/for/for6.test index 42f99b3dda73..a11b71a8cfa0 100644 --- a/plugins/groovy/testdata/parsing/groovy/statements/for/for6.test +++ b/plugins/groovy/testdata/parsing/groovy/statements/for/for6.test @@ -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