/* * Parses Groovy-style 'in' clause */ private static boolean forInClauseParse(PsiBuilder builder, GroovyParser parser) { PsiBuilder.Marker marker = builder.mark(); PsiBuilder.Marker declMarker = builder.mark(); if (ParserUtils.lookAhead(builder, mIDENT, kIN)) { ParserUtils.eatElement(builder, PARAMETER); declMarker.drop(); ParserUtils.getToken(builder, kIN); if (!ShiftExpression.parse(builder, parser)) { builder.error(GroovyBundle.message("expression.expected")); } marker.done(FOR_IN_CLAUSE); return true; } if (DeclarationStart.parse(builder, parser)) { if (Modifiers.parse(builder, parser)) { TypeSpec.parse(builder); return singleDeclNoInitParse(builder, marker, declMarker, parser); } } if (TypeSpec.parse(builder)) { return singleDeclNoInitParse(builder, marker, declMarker, parser); } declMarker.drop(); marker.drop(); return false; }
@Nullable public static IElementType parseAfterModifiers( PsiBuilder builder, boolean isInClass, boolean isInAnnotation, GroovyParser parser, PsiBuilder.Marker declMarker, boolean modifiersParsed) { if (modifiersParsed && mLT == builder.getTokenType()) { TypeParameters.parse(builder); PsiBuilder.Marker checkMarker = builder.mark(); // point to begin of type or variable if (TypeSpec.parse(builder, true) == fail) { // if type wasn't recognized trying parse VariableDeclaration checkMarker.rollbackTo(); } else { checkMarker.drop(); } IElementType decl = VariableDefinitions.parseDefinitions( builder, isInClass, false, false, true, modifiersParsed, false, parser); if (WRONGWAY.equals(decl)) { return WRONGWAY; } return METHOD_DEFINITION; } if (modifiersParsed) { PsiBuilder.Marker checkMarker = builder.mark(); // point to begin of type or variable if (TypeSpec.parse(builder, false) == fail) { // if type wasn't recognized trying parse VariableDeclaration checkMarker.rollbackTo(); if (isInAnnotation) { builder.error(GroovyBundle.message("type.expected")); } // current token isn't identifier IElementType varDecl = VariableDefinitions.parse(builder, isInClass, modifiersParsed, parser); if (WRONGWAY.equals(varDecl)) { return WRONGWAY; } return varDecl; } else { // type was recognized, identifier here // starts after type IElementType varDeclarationTop = VariableDefinitions.parse(builder, isInClass, modifiersParsed, false, parser); if (WRONGWAY.equals(varDeclarationTop)) { checkMarker.rollbackTo(); if (isInAnnotation) { builder.error(GroovyBundle.message("type.expected")); } // starts before "type" identifier, here can't be tuple, because next token is identifier // (we are in "type recognized" branch) IElementType varDecl = VariableDefinitions.parse(builder, isInClass, modifiersParsed, false, parser); if (WRONGWAY.equals(varDecl)) { return WRONGWAY; } else { return varDecl; } } else { checkMarker.drop(); return varDeclarationTop; } } } else { // if definition starts with lower case letter than it can be just call expression String text = builder.getTokenText(); if (!builder.eof() && !TokenSets.BUILT_IN_TYPE.contains(builder.getTokenType()) && text != null && (Character.isLowerCase((text.charAt(0))) || !Character.isLetter(text.charAt(0))) && (ParserUtils.lookAhead(builder, mIDENT, mIDENT) || ParserUtils.lookAhead(builder, mIDENT, mLPAREN))) { // call expression return WRONGWAY; } boolean typeParsed = false; if (!ParserUtils.lookAhead(builder, mIDENT, mLPAREN)) { typeParsed = TypeSpec.parse(builder, true) != fail; // type specification starts with upper case letter if (!typeParsed) { builder.error(GroovyBundle.message("type.specification.expected")); return WRONGWAY; } } IElementType varDef = VariableDefinitions.parseDefinitions( builder, isInClass, false, false, false, typeParsed, false, parser); if (varDef != WRONGWAY) { return varDef; } else if (isInClass && typeParsed) { return typeParsed ? null : WRONGWAY; } return WRONGWAY; } }