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 47e432f781c9..36037d231020 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 @@ -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; + } + /* ********************************************************** */ // <> 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; } 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 0634d5648619..c5b10c44da1b 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 @@ -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"); 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 737af0f3e109..458db354e1e3 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 @@ -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); 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 b5febb927c57..7ed615fbd71e 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 @@ -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 ::= <> | < expected + \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/relational/inNegated.test b/plugins/groovy/testdata/parsing/groovy/expressions/relational/inNegated.test new file mode 100644 index 000000000000..6f38f5bb0816 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/relational/inNegated.test @@ -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') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/relational/instanceOfNegated.test b/plugins/groovy/testdata/parsing/groovy/expressions/relational/instanceOfNegated.test new file mode 100644 index 000000000000..94b19b6c4f19 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/relational/instanceOfNegated.test @@ -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') \ No newline at end of file