[groovy] parse negated in and instanceof (IDEA-188424)

This commit is contained in:
Daniil Ovchinnikov
2018-05-28 18:21:02 +03:00
parent c8d9642150
commit 5fc6874352
12 changed files with 144 additions and 35 deletions
@@ -269,12 +269,12 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser {
BAND_EXPRESSION, BOR_EXPRESSION, BUILT_IN_TYPE_EXPRESSION, CAST_EXPRESSION,
CLOSURE, CONSTRUCTOR_CALL_EXPRESSION, ELVIS_EXPRESSION, EQUALITY_EXPRESSION,
EXPRESSION, GSTRING, INDEX_EXPRESSION, INSTANCEOF_EXPRESSION,
LAND_EXPRESSION, LIST_OR_MAP, LITERAL, LOR_EXPRESSION,
METHOD_CALL_EXPRESSION, MULTIPLICATIVE_EXPRESSION, NEW_EXPRESSION, PARENTHESIZED_EXPRESSION,
POWER_EXPRESSION, PROPERTY_EXPRESSION, RANGE_EXPRESSION, REFERENCE_EXPRESSION,
REGEX, REGEX_FIND_EXPRESSION, REGEX_MATCH_EXPRESSION, RELATIONAL_EXPRESSION,
SHIFT_EXPRESSION, TERNARY_EXPRESSION, TUPLE_ASSIGNMENT_EXPRESSION, UNARY_EXPRESSION,
XOR_EXPRESSION),
IN_EXPRESSION, LAND_EXPRESSION, LIST_OR_MAP, LITERAL,
LOR_EXPRESSION, METHOD_CALL_EXPRESSION, MULTIPLICATIVE_EXPRESSION, NEW_EXPRESSION,
PARENTHESIZED_EXPRESSION, POWER_EXPRESSION, PROPERTY_EXPRESSION, RANGE_EXPRESSION,
REFERENCE_EXPRESSION, REGEX, REGEX_FIND_EXPRESSION, REGEX_MATCH_EXPRESSION,
RELATIONAL_EXPRESSION, SHIFT_EXPRESSION, TERNARY_EXPRESSION, TUPLE_ASSIGNMENT_EXPRESSION,
UNARY_EXPRESSION, XOR_EXPRESSION),
};
/* ********************************************************** */
@@ -3758,6 +3758,40 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser {
return r;
}
/* ********************************************************** */
// mb_not ('instanceof') (type_element | expect_type)
static boolean instanceof_expression_tail(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "instanceof_expression_tail")) return false;
if (!nextTokenIsFast(b, T_NOT, KW_INSTANCEOF)) return false;
boolean r, p;
Marker m = enter_section_(b, l, _NONE_);
r = mb_not(b, l + 1);
r = r && instanceof_expression_tail_1(b, l + 1);
p = r; // pin = 2
r = r && instanceof_expression_tail_2(b, l + 1);
exit_section_(b, l, m, r, p, null);
return r || p;
}
// ('instanceof')
private static boolean instanceof_expression_tail_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "instanceof_expression_tail_1")) return false;
boolean r;
Marker m = enter_section_(b);
r = consumeTokenFast(b, KW_INSTANCEOF);
exit_section_(b, m, null, r);
return r;
}
// type_element | expect_type
private static boolean instanceof_expression_tail_2(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "instanceof_expression_tail_2")) return false;
boolean r;
r = type_element(b, l + 1);
if (!r) r = expect_type(b, l + 1);
return r;
}
/* ********************************************************** */
// <<classIdentifier>> type_parameter_list? nl_extends nl_non_empty_implements?
static boolean interface_definition_header(PsiBuilder b, int l) {
@@ -3940,6 +3974,14 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser {
return r;
}
/* ********************************************************** */
// '!'?
static boolean mb_not(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "mb_not")) return false;
consumeTokenFast(b, T_NOT);
return true;
}
/* ********************************************************** */
// '?'?
static boolean mb_question(PsiBuilder b, int l) {
@@ -5097,7 +5139,7 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
// '<' !'<' | '<=' | '>' !'>' | '>=' | 'in'
// '<' !'<' | '<=' | '>' !'>' | '>='
static boolean relational_operator(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "relational_operator")) return false;
boolean r;
@@ -5106,7 +5148,6 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser {
if (!r) r = consumeTokenFast(b, T_LE);
if (!r) r = relational_operator_2(b, l + 1);
if (!r) r = consumeTokenFast(b, T_GE);
if (!r) r = consumeTokenFast(b, KW_IN);
exit_section_(b, m, null, r);
return r;
}
@@ -6592,7 +6633,7 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser {
// 5: BINARY(xor_expression)
// 6: BINARY(band_expression)
// 7: BINARY(equality_expression) BINARY(compare_expression) BINARY(regex_find_expression) BINARY(regex_match_expression)
// 8: BINARY(relational_expression) POSTFIX(instanceof_expression) POSTFIX(as_expression)
// 8: BINARY(relational_expression) BINARY(in_expression) POSTFIX(instanceof_expression) POSTFIX(as_expression)
// 9: BINARY(shift_expression) BINARY(range_expression)
// 10: BINARY(additive_expression)
// 11: BINARY(multiplicative_expression)
@@ -6688,7 +6729,11 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser {
r = expression(b, l, 8);
exit_section_(b, l, m, RELATIONAL_EXPRESSION, r, true, null);
}
else if (g < 8 && instanceof_expression_0(b, l + 1)) {
else if (g < 8 && in_expression_0(b, l + 1)) {
r = expression(b, l, 8);
exit_section_(b, l, m, IN_EXPRESSION, r, true, null);
}
else if (g < 8 && instanceof_expression_tail(b, l + 1)) {
r = true;
exit_section_(b, l, m, INSTANCEOF_EXPRESSION, r, true, null);
}
@@ -6842,24 +6887,24 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser {
return r;
}
// 'instanceof' (type_element | expect_type)
private static boolean instanceof_expression_0(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "instanceof_expression_0")) return false;
boolean r, p;
Marker m = enter_section_(b, l, _NONE_);
r = consumeTokenSmart(b, KW_INSTANCEOF);
p = r; // pin = 1
r = r && instanceof_expression_0_1(b, l + 1);
exit_section_(b, l, m, r, p, null);
return r || p;
// mb_not ('in')
private static boolean in_expression_0(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "in_expression_0")) return false;
boolean r;
Marker m = enter_section_(b);
r = mb_not(b, l + 1);
r = r && in_expression_0_1(b, l + 1);
exit_section_(b, m, null, r);
return r;
}
// type_element | expect_type
private static boolean instanceof_expression_0_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "instanceof_expression_0_1")) return false;
// ('in')
private static boolean in_expression_0_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "in_expression_0_1")) return false;
boolean r;
r = type_element(b, l + 1);
if (!r) r = expect_type(b, l + 1);
Marker m = enter_section_(b);
r = consumeTokenSmart(b, KW_IN);
exit_section_(b, m, null, r);
return r;
}
@@ -102,6 +102,7 @@ public interface GroovyElementTypes {
GroovyElementType INDEX_EXPRESSION = new GroovyElementType("INDEX_EXPRESSION");
GroovyElementType INSTANCEOF_EXPRESSION = new GroovyElementType("INSTANCEOF_EXPRESSION");
GrInterfaceDefinitionElementType INTERFACE_TYPE_DEFINITION = new GrInterfaceDefinitionElementType("INTERFACE_TYPE_DEFINITION");
GroovyElementType IN_EXPRESSION = new GroovyElementType("IN_EXPRESSION");
GroovyElementType LABELED_STATEMENT = new GroovyElementType("LABELED_STATEMENT");
GroovyElementType LAND_EXPRESSION = new GroovyElementType("LAND_EXPRESSION");
GroovyElementType LEFT_SHIFT_SIGN = new GroovyElementType("LEFT_SHIFT_SIGN");
@@ -9,6 +9,7 @@ import org.jetbrains.plugins.groovy.lang.groovydoc.lexer.IGroovyDocElementType;
import org.jetbrains.plugins.groovy.lang.groovydoc.psi.GroovyDocPsiCreator;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyElementType;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrImportAliasImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrInExpressionImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyASTPsiElementImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.GrListOrMapImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.GrThrowsClauseImpl;
@@ -182,6 +183,7 @@ public class GroovyPsiCreator {
if (elem == REGEX_FIND_EXPRESSION) return new GrRegexFindExpressionImpl(node);
if (elem == EQUALITY_EXPRESSION) return new GrRelationalExpressionImpl(node);
if (elem == RELATIONAL_EXPRESSION) return new GrRelationalExpressionImpl(node);
if (elem == IN_EXPRESSION) return new GrInExpressionImpl(node);
if (elem == SHIFT_EXPRESSION) return new GrShiftExpressionImpl(node);
if (elem == RANGE_EXPRESSION) return new GrRangeExpressionImpl(node);
if (elem == ADDITIVE_EXPRESSION) return new GrAdditiveExpressionImpl(node);
@@ -176,6 +176,7 @@
elementType('.*_reference_expression') = reference_expression
elementType('.*_class_type_element') = class_type_element
consumeTokenMethod('.*_expression') = 'consumeTokenFast'
consumeTokenMethod('.*_expression_tail') = 'consumeTokenFast'
consumeTokenMethod('.*_shift.*_sign') = 'consumeTokenFast'
consumeTokenMethod('fast.*') = 'consumeTokenFast'
consumeTokenMethod('.*_type_definition') = 'consumeTokenFast'
@@ -1039,14 +1040,12 @@ right_shift_sign ::= '>' '>'
right_shift_unsigned_sign ::= '>' '>' '>'
range_expression ::= expression ('..' | '..<') expression
private priority7 ::= relational_expression | instanceof_expression | as_expression
private priority7 ::= relational_expression | in_expression | instanceof_expression | as_expression
relational_expression ::= expression relational_operator mb_nl expression
private relational_operator ::= '<' !'<' | '<=' | '>' !'>' | '>=' | 'in' { consumeTokenMethod = 'consumeTokenFast' }
instanceof_expression ::= expression ('instanceof' (type_element | expect_type))
{
pin('.*') = 1
}
private relational_operator ::= '<' !'<' | '<=' | '>' !'>' | '>=' { consumeTokenMethod = 'consumeTokenFast' }
in_expression ::= expression mb_not ('in') expression
instanceof_expression ::= expression instanceof_expression_tail
private instanceof_expression_tail ::= mb_not ('instanceof') (type_element | expect_type) { pin = 2 }
as_expression ::= expression 'as' type_element
private priority8 ::= equality_expression | compare_expression | regex_find_expression | regex_match_expression
@@ -1239,6 +1238,7 @@ private meta mb_nl_group ::= <<something>> | <<withProtectedLastVariantPos (nl <
private empty ::= ()
private mb_question ::= '?'? { consumeTokenMethod = 'consumeTokenFast' }
private mb_not ::= '!'? { consumeTokenMethod = 'consumeTokenFast' }
private fast_colon ::= ':'
private fast_comma ::= ','
@@ -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.api.statements.expressions.GrBinaryExpression;
public interface GrInExpression extends GrBinaryExpression {
}
@@ -0,0 +1,11 @@
// 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.GrInExpression
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrBinaryExpressionImpl
class GrInExpressionImpl(node: ASTNode) : GrBinaryExpressionImpl(node), GrInExpression {
override fun toString(): String = "${javaClass.simpleName}(${node.elementType})"
}
@@ -464,6 +464,12 @@ class ExpressionsParsingTest extends GroovyParsingTestCase {
void testrelational$noRValue() { doTest() }
void testrelational$exclamationAfterExpression() { doTest() }
void testrelational$inNegated() { doTest() }
void testrelational$instanceOfNegated() { doTest() }
void testspecial$grvy1173() throws Throwable { doTest() }
void testspecial$list1() throws Throwable { doTest() }
@@ -3,9 +3,9 @@ if (i in String) i = i.substring(2)
0(1) element: null
1(2) element: IF statement
2(3) READ i
3(4,6) Condition Relational expression
3(4,6) Condition GrInExpressionImpl(IN_EXPRESSION)
4(5) instanceof: i in String
5(10) Negating goto instruction, condition=3Relational expression
5(10) Negating goto instruction, condition=3GrInExpressionImpl(IN_EXPRESSION)
6(7) instanceof: i in String
7(8) READ i
8(9) WRITE i
@@ -10,7 +10,7 @@ Groovy script
PsiWhiteSpace(' ')
PsiElement(=)('=')
PsiWhiteSpace(' ')
Relational expression
GrInExpressionImpl(IN_EXPRESSION)
Method call
Reference expression
PsiElement(identifier)('abc')
@@ -0,0 +1,12 @@
a !
-----
Groovy script
Call expression
Reference expression
PsiElement(identifier)('a')
PsiWhiteSpace(' ')
Command arguments
Unary expression
PsiElement(!)('!')
PsiErrorElement:<expression> expected
<empty list>
@@ -0,0 +1,12 @@
a !in b
-----
Groovy script
GrInExpressionImpl(IN_EXPRESSION)
Reference expression
PsiElement(identifier)('a')
PsiWhiteSpace(' ')
PsiElement(!)('!')
PsiElement(in)('in')
PsiWhiteSpace(' ')
Reference expression
PsiElement(identifier)('b')
@@ -0,0 +1,13 @@
a !instanceof b
-----
Groovy script
Instanceof expression
Reference expression
PsiElement(identifier)('a')
PsiWhiteSpace(' ')
PsiElement(!)('!')
PsiElement(instanceof)('instanceof')
PsiWhiteSpace(' ')
Type element
Reference element
PsiElement(identifier)('b')