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 d4c18d899ee5..9035b775cdcf 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 @@ -1758,6 +1758,44 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { return r; } + /* ********************************************************** */ + // priority1_4 <> | clear_variants_and_fail | cast_parenthesized_expression + static boolean cast_operand(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "cast_operand")) return false; + boolean r; + Marker m = enter_section_(b); + r = cast_operand_0(b, l + 1); + if (!r) r = clear_variants_and_fail(b, l + 1); + if (!r) r = cast_parenthesized_expression(b, l + 1); + exit_section_(b, m, null, r); + return r; + } + + // priority1_4 <> + private static boolean cast_operand_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "cast_operand_0")) return false; + boolean r; + Marker m = enter_section_(b); + r = expression(b, l + 1, 13); + r = r && noParenthesized(b, l + 1); + exit_section_(b, m, null, r); + return r; + } + + /* ********************************************************** */ + // '(' expression ')' + public static boolean cast_parenthesized_expression(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "cast_parenthesized_expression")) return false; + if (!nextTokenIsFast(b, T_LPAREN)) return false; + boolean r; + Marker m = enter_section_(b); + r = consumeTokenFast(b, T_LPAREN); + r = r && expression(b, l + 1, -1); + r = r && consumeToken(b, T_RPAREN); + exit_section_(b, m, PARENTHESIZED_EXPRESSION, r); + return r; + } + /* ********************************************************** */ // 'catch' '(' parse_catch_parameter ')' lazy_block public static boolean catch_clause(PsiBuilder b, int l) { @@ -7256,14 +7294,17 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { return r; } - // &cast_expression_start ('(' type_element ')' priority1_4) + // &cast_expression_start '(' type_element ')' cast_operand public static boolean cast_expression(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "cast_expression")) return false; if (!nextTokenIsSmart(b, T_LPAREN)) return false; boolean r; Marker m = enter_section_(b); r = cast_expression_0(b, l + 1); - r = r && cast_expression_1(b, l + 1); + r = r && consumeTokenSmart(b, T_LPAREN); + r = r && type_element(b, l + 1); + r = r && consumeToken(b, T_RPAREN); + r = r && cast_operand(b, l + 1); exit_section_(b, m, CAST_EXPRESSION, r); return r; } @@ -7278,19 +7319,6 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { return r; } - // '(' type_element ')' priority1_4 - private static boolean cast_expression_1(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "cast_expression_1")) return false; - boolean r; - Marker m = enter_section_(b); - r = consumeTokenSmart(b, T_LPAREN); - r = r && type_element(b, l + 1); - r = r && consumeToken(b, T_RPAREN); - r = r && expression(b, l + 1, 13); - exit_section_(b, m, null, r); - return r; - } - // fast_question index_expression_argument_list not_colon private static boolean safe_index_expression_0(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "safe_index_expression_0")) return false; 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 d559457cd71c..99f769b0b28a 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 @@ -985,8 +985,10 @@ private property_expression_identifiers ::= parenthesized_expression | lazy_bloc private priority1_4 ::= not_expression | cast_expression not_expression ::= ('~' | '!') expression { elementType = unary_expression } -cast_expression ::= &cast_expression_start ('(' type_element ')' priority1_4) +cast_expression ::= &cast_expression_start '(' type_element ')' cast_operand private cast_expression_start ::= '(' (IDENTIFIER | primitive_type) { consumeTokenMethod = 'consumeTokenFast' } +private cast_operand ::= priority1_4 <> | clear_variants_and_fail | cast_parenthesized_expression +cast_parenthesized_expression ::= '(' expression ')' { elementType = parenthesized_expression } private priority1_5 ::= index_expression | safe_index_expression | postfix_unary_expression index_expression ::= expression index_expression_argument_list diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/parserUtils.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/parserUtils.kt index 21aa60576ae2..d87a66a04e3d 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/parserUtils.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/parserUtils.kt @@ -403,3 +403,7 @@ fun newLine(builder: PsiBuilder, level: Int): Boolean { } fun noNewLine(builder: PsiBuilder, level: Int): Boolean = !newLine(builder, level) + +fun noParenthesized(builder: PsiBuilder, level: Int): Boolean { + return builder.latestDoneMarker?.tokenType != PARENTHESIZED_EXPRESSION +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy index 0d803fd646c8..959db55019fd 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy @@ -530,6 +530,16 @@ class ExpressionsParsingTest extends GroovyParsingTestCase { void testtypecast$noExpression() { doTest() } + void testtypecast$parenthesizedOperand() { doTest() } + + void testtypecast$parenthesizedQualifier() { doTest() } + + void testtypecast$parenthesizedOperandError() { doTest() } + + void testtypecast$nested() { doTest() } + + void testtypecast$vsMethodCall() { doTest() } + void testtypecast$conditional() throws Throwable { doTest() } void testAtHang() throws Throwable { doTest() } diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/typecast/nested.test b/plugins/groovy/testdata/parsing/groovy/expressions/typecast/nested.test new file mode 100644 index 000000000000..5a95b9f5e033 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/typecast/nested.test @@ -0,0 +1,20 @@ +(a)(b)(c) +----- +Groovy script + Typecast expression + PsiElement(()('(') + Type element + Reference element + PsiElement(identifier)('a') + PsiElement())(')') + Typecast expression + PsiElement(()('(') + Type element + Reference element + PsiElement(identifier)('b') + PsiElement())(')') + Parenthesized expression + PsiElement(()('(') + Reference expression + PsiElement(identifier)('c') + PsiElement())(')') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/typecast/parenthesizedOperand.test b/plugins/groovy/testdata/parsing/groovy/expressions/typecast/parenthesizedOperand.test new file mode 100644 index 000000000000..49b1abef8e3c --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/typecast/parenthesizedOperand.test @@ -0,0 +1,42 @@ +(a)() +(a)(1) +(a)(1, 2) +----- +Groovy script + Method call + Parenthesized expression + PsiElement(()('(') + Reference expression + PsiElement(identifier)('a') + PsiElement())(')') + Arguments + PsiElement(()('(') + PsiElement())(')') + PsiElement(new line)('\n') + Typecast expression + PsiElement(()('(') + Type element + Reference element + PsiElement(identifier)('a') + PsiElement())(')') + Parenthesized expression + PsiElement(()('(') + Literal + PsiElement(Integer)('1') + PsiElement())(')') + PsiElement(new line)('\n') + Method call + Parenthesized expression + PsiElement(()('(') + Reference expression + PsiElement(identifier)('a') + PsiElement())(')') + Arguments + PsiElement(()('(') + Literal + PsiElement(Integer)('1') + PsiElement(,)(',') + PsiWhiteSpace(' ') + Literal + PsiElement(Integer)('2') + PsiElement())(')') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/typecast/parenthesizedOperandError.test b/plugins/groovy/testdata/parsing/groovy/expressions/typecast/parenthesizedOperandError.test new file mode 100644 index 000000000000..abcc10991e74 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/typecast/parenthesizedOperandError.test @@ -0,0 +1,20 @@ +(a)(1 + ) +----- +Groovy script + Typecast expression + PsiElement(()('(') + Type element + Reference element + PsiElement(identifier)('a') + PsiElement())(')') + Parenthesized expression + PsiElement(()('(') + Additive expression + Literal + PsiElement(Integer)('1') + PsiWhiteSpace(' ') + PsiElement(+)('+') + PsiErrorElement: expected, got ')' + + PsiWhiteSpace(' ') + PsiElement())(')') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/typecast/parenthesizedQualifier.test b/plugins/groovy/testdata/parsing/groovy/expressions/typecast/parenthesizedQualifier.test new file mode 100644 index 000000000000..681d96afea70 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/typecast/parenthesizedQualifier.test @@ -0,0 +1,17 @@ +(a)(b).c +----- +Groovy script + Typecast expression + PsiElement(()('(') + Type element + Reference element + PsiElement(identifier)('a') + PsiElement())(')') + Reference expression + Parenthesized expression + PsiElement(()('(') + Reference expression + PsiElement(identifier)('b') + PsiElement())(')') + PsiElement(.)('.') + PsiElement(identifier)('c') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/typecast/vsMethodCall.test b/plugins/groovy/testdata/parsing/groovy/expressions/typecast/vsMethodCall.test new file mode 100644 index 000000000000..0d6ff1b0d3a4 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/typecast/vsMethodCall.test @@ -0,0 +1,19 @@ +(a) b (c) +----- +Groovy script + Typecast expression + PsiElement(()('(') + Type element + Reference element + PsiElement(identifier)('a') + PsiElement())(')') + PsiWhiteSpace(' ') + Method call + Reference expression + PsiElement(identifier)('b') + PsiWhiteSpace(' ') + Arguments + PsiElement(()('(') + Reference expression + PsiElement(identifier)('c') + PsiElement())(')') \ No newline at end of file