[groovy] fix parsing of parenthesized cast operand (IDEA-194587)

This commit is contained in:
Daniil Ovchinnikov
2018-06-26 16:59:27 +03:00
parent 78a8978dd6
commit e76238a180
9 changed files with 178 additions and 16 deletions
@@ -1758,6 +1758,44 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser {
return r;
}
/* ********************************************************** */
// priority1_4 <<noParenthesized>> | 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 <<noParenthesized>>
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;
@@ -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 <<noParenthesized>> | 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
@@ -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
}
@@ -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() }
@@ -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())(')')
@@ -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())(')')
@@ -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:<expression> expected, got ')'
<empty list>
PsiWhiteSpace(' ')
PsiElement())(')')
@@ -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')
@@ -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())(')')