/** * Named list operators * * @param b PerlBuilder * @param l Parsing level * @return parsing result */ public static boolean isListOperator(PsiBuilder b, int l) { PerlTokenData prevTokenData = ((PerlBuilder) b).lookupToken(-1); if (prevTokenData != null && prevTokenData.getTokenType() == OPERATOR_DEREFERENCE) return false; IElementType tokenType = b.getTokenType(); IElementType nextTokenType = b.lookAhead(1); if (CONVERTABLE_TOKENS.contains(tokenType) && nextTokenType != LEFT_PAREN // not function call && !PACKAGE_TOKENS.contains(nextTokenType) // not method Package:: && !(nextTokenType == IDENTIFIER && ((PerlBuilder) b) .isKnownPackage( ((PerlBuilder) b).lookupToken(1).getTokenText())) // not Method Package ) // todo we should check current namespace here return !PerlSubUtil.BUILT_IN_UNARY.contains(b.getTokenText()); else if (PACKAGE_TOKENS.contains(tokenType) && CONVERTABLE_TOKENS.contains(nextTokenType) && b.lookAhead(2) != LEFT_PAREN) return !PerlSubUtil.isUnary( b.getTokenText(), ((PerlBuilder) b).lookupToken(1).getTokenText()); return false; }
@Nullable private PsiBuilder.Marker parseLambdaAfterParenth( final PsiBuilder builder, @Nullable final PsiBuilder.Marker typeList) { final boolean isLambda; final boolean isTyped; final IElementType nextToken1 = builder.lookAhead(1); final IElementType nextToken2 = builder.lookAhead(2); if (nextToken1 == JavaTokenType.RPARENTH && nextToken2 == JavaTokenType.ARROW) { isLambda = true; isTyped = false; } else if (nextToken1 == JavaTokenType.AT || ElementType.MODIFIER_BIT_SET.contains(nextToken1) || ElementType.PRIMITIVE_TYPE_BIT_SET.contains(nextToken1)) { isLambda = true; isTyped = true; } else if (nextToken1 == JavaTokenType.IDENTIFIER) { if (nextToken2 == JavaTokenType.COMMA || nextToken2 == JavaTokenType.RPARENTH && builder.lookAhead(3) == JavaTokenType.ARROW) { isLambda = true; isTyped = false; } else if (nextToken2 == JavaTokenType.ARROW) { isLambda = false; isTyped = false; } else { boolean arrow = false; final PsiBuilder.Marker marker = builder.mark(); while (!builder.eof()) { builder.advanceLexer(); final IElementType tokenType = builder.getTokenType(); if (tokenType == JavaTokenType.ARROW) { arrow = true; break; } if (tokenType == JavaTokenType.RPARENTH) { arrow = builder.lookAhead(1) == JavaTokenType.ARROW; break; } else if (tokenType == JavaTokenType.LPARENTH || tokenType == JavaTokenType.SEMICOLON || tokenType == JavaTokenType.LBRACE || tokenType == JavaTokenType.RBRACE) { break; } } marker.rollbackTo(); isLambda = arrow; isTyped = true; } } else { isLambda = false; isTyped = false; } return isLambda ? parseLambdaExpression(builder, isTyped, typeList) : null; }
/** * Statement recovery function. Should not consume token, only check; * * @param b PerlBuilder * @param l parsing level * @return parsing result */ public static boolean recoverStatement(PsiBuilder b, int l) { assert b instanceof PerlBuilder; if (!((PerlBuilder) b).isRecoveringStatement()) ((PerlBuilder) b).startRecovery(); IElementType currentTokenType = b.getTokenType(); // System.err.println("Checking " + b.getTokenText() + currentTokenType); if (currentTokenType == null // got end of file || ((PerlBuilder) b).getBracesLevel() == 0 && ( // we are not in braced statement UNCONDITIONAL_STATEMENT_RECOVERY_TOKENS.contains( currentTokenType) // got semi, package, end of regex, use, compound or suffix || currentTokenType == RESERVED_SUB && STATEMENT_RECOVERY_SUB_SUFFIX.contains(b.lookAhead(1)) // got sub definition )) { ((PerlBuilder) b).stopRecovery(); return false; } if (currentTokenType == LEFT_BRACE) ((PerlBuilder) b).openBrace(); else if (currentTokenType == RIGHT_BRACE) ((PerlBuilder) b).closeBrace(); return true; }
/** * Parsing label declaration LABEL: * * @param b PerlBuilder * @param l parsing level * @return parsing result */ public static boolean parseLabelDeclaration(PsiBuilder b, int l) { if (CONVERTABLE_TOKENS.contains(b.getTokenType()) && b.lookAhead(1) == COLON) { PsiBuilder.Marker m = b.mark(); b.advanceLexer(); m.collapse(LABEL); b.advanceLexer(); return true; } return false; }
public static boolean convertBracedString(PsiBuilder b, int l) { if (CONVERTABLE_TOKENS.contains(b.getTokenType()) && b.lookAhead(1) == RIGHT_BRACE) { // fixme shouldn't we add string_sq here? PsiBuilder.Marker m = b.mark(); b.advanceLexer(); m.collapse(STRING_CONTENT); return true; } return false; }
public static boolean parseAmbiguousSigil(PsiBuilder b, int l, IElementType sigilTokenType) { IElementType tokenType = b.getTokenType(); if (tokenType == sigilTokenType) { if (PerlParserDefinition.WHITE_SPACE_AND_COMMENTS.contains(b.rawLookup(1)) && b.lookAhead(1) != LEFT_BRACE) // space disallowed after * or % if it's not a cast return false; b.advanceLexer(); return true; } return false; }
/** * Checks and parses bareword filehandle for <FH> operations * * @param b PerlBuilder * @param l parsing level * @return parsing result */ public static boolean parseReadHandle(PsiBuilder b, int l) { IElementType currentTokenType = b.getTokenType(); IElementType nextTokenType = b.lookAhead(1); if (CONVERTABLE_TOKENS.contains(currentTokenType) && nextTokenType == OPERATOR_GT_NUMERIC) { PsiBuilder.Marker m = b.mark(); b.advanceLexer(); m.collapse(HANDLE); return true; } return false; }
/** * Named unary operators * * @param b PerlBuilder * @param l parsing level * @return parsing result */ public static boolean isUnaryOperator(PsiBuilder b, int l) { assert b instanceof PerlBuilder; PerlTokenData prevTokenData = ((PerlBuilder) b).lookupToken(-1); if (prevTokenData != null && prevTokenData.getTokenType() == OPERATOR_DEREFERENCE) return false; IElementType tokenType = b.getTokenType(); IElementType nextTokenType = b.lookAhead(1); if (CONVERTABLE_TOKENS.contains(tokenType) && nextTokenType != LEFT_PAREN && !PACKAGE_TOKENS.contains(nextTokenType)) // todo we should check current namespace here return PerlSubUtil.BUILT_IN_UNARY.contains(b.getTokenText()); else if (PACKAGE_TOKENS.contains(tokenType) && CONVERTABLE_TOKENS.contains(SUB) && b.lookAhead(2) != LEFT_PAREN) { PerlTokenData nextToken = ((PerlBuilder) b).lookupToken(1); if (nextToken != null) return PerlSubUtil.isUnary(b.getTokenText(), nextToken.getTokenText()); } return false; }
public static void parseInclude(PsiBuilder builder) { PsiBuilder.Marker marker = builder.mark(); IElementType nextElement = builder.lookAhead(1); if (nextElement != STRING_LITERAL && nextElement != STRING_INCLUDE_LITERAL) builder.error("Incorrect include name"); else builder.advanceLexer(); builder.advanceLexer(); done( marker, nextElement == STRING_LITERAL ? CPsiSharpInclude.class : CPsiSharpIndepInclude.class); skipLines(builder); }
/** * parser for print/say/printf filehandle * * @param b PerlBuilder * @param l parsing level * @return parsing result */ public static boolean parsePrintHandle(PsiBuilder b, int l) { IElementType currentTokenType = b.getTokenType(); IElementType nextTokenType = b.lookAhead(1); assert b instanceof PerlBuilder; if (CONVERTABLE_TOKENS.contains(currentTokenType) // it's identifier && !PRINT_HANDLE_NEGATE_SUFFIX.contains(nextTokenType) // no negation tokens && !PerlSubUtil.BUILT_IN.contains( b.getTokenText()) // it's not built in. crude, probably we should check any known sub ) { PsiBuilder.Marker m = b.mark(); b.advanceLexer(); m.collapse(HANDLE); return true; } return false; }
/** * Merges sequence [package] identifier to a package * * @param b PerlBuilder * @param l parsing level * @return result */ public static boolean mergePackageName(PsiBuilder b, int l) { IElementType tokenType = b.getTokenType(); if (tokenType == PACKAGE) { b.advanceLexer(); return true; } else if (PACKAGE_TOKENS.contains(tokenType) && CONVERTABLE_TOKENS.contains(b.lookAhead(1))) { PsiBuilder.Marker m = b.mark(); b.advanceLexer(); b.advanceLexer(); m.collapse(PACKAGE); return true; } else if (PACKAGE_TOKENS.contains(tokenType) // explicit package name, like Foo::->method() || CONVERTABLE_TOKENS.contains(tokenType) // single word package ) { PsiBuilder.Marker m = b.mark(); b.advanceLexer(); m.collapse(PACKAGE); return true; } return false; }
@Nullable public IElementType lookAhead(int step) { return myBuilder.lookAhead(step); }
@Nullable private PsiBuilder.Marker parsePrimaryExpressionStart(final PsiBuilder builder) { IElementType tokenType = builder.getTokenType(); if (LITERALS.contains(tokenType)) { final PsiBuilder.Marker literal = builder.mark(); builder.advanceLexer(); literal.done(JavaElementType.LITERAL_EXPRESSION); return literal; } if (tokenType == JavaTokenType.LBRACE) { return parseArrayInitializer(builder); } if (tokenType == JavaTokenType.NEW_KEYWORD) { return parseNew(builder, null); } if (tokenType == JavaTokenType.LPARENTH) { final PsiBuilder.Marker lambda = parseLambdaAfterParenth(builder, null); if (lambda != null) { return lambda; } final PsiBuilder.Marker parenth = builder.mark(); builder.advanceLexer(); final PsiBuilder.Marker inner = parse(builder); if (inner == null) { error(builder, JavaErrorMessages.message("expected.expression")); } if (!expect(builder, JavaTokenType.RPARENTH)) { if (inner != null) { error(builder, JavaErrorMessages.message("expected.rparen")); } } parenth.done(JavaElementType.PARENTH_EXPRESSION); return parenth; } if (TYPE_START.contains(tokenType)) { final PsiBuilder.Marker mark = builder.mark(); final ReferenceParser.TypeInfo typeInfo = myParser.getReferenceParser().parseTypeInfo(builder, 0); if (typeInfo != null) { boolean optionalClassKeyword = typeInfo.isPrimitive || typeInfo.isArray; if (optionalClassKeyword || !typeInfo.hasErrors && typeInfo.isParameterized) { final PsiBuilder.Marker result = continueClassAccessOrMethodReference(builder, mark, optionalClassKeyword); if (result != null) { return result; } } } mark.rollbackTo(); } PsiBuilder.Marker annotation = null; if (tokenType == JavaTokenType.AT) { annotation = myParser.getDeclarationParser().parseAnnotations(builder); tokenType = builder.getTokenType(); } if (tokenType == JavaTokenType.IDENTIFIER) { if (builder.lookAhead(1) == JavaTokenType.ARROW) { return parseLambdaExpression(builder, false, null); } final PsiBuilder.Marker refExpr; if (annotation != null) { final PsiBuilder.Marker refParam = annotation.precede(); refParam.doneBefore(JavaElementType.REFERENCE_PARAMETER_LIST, annotation); refExpr = refParam.precede(); } else { refExpr = builder.mark(); builder.mark().done(JavaElementType.REFERENCE_PARAMETER_LIST); } builder.advanceLexer(); refExpr.done(JavaElementType.REFERENCE_EXPRESSION); return refExpr; } if (annotation != null) { annotation.rollbackTo(); tokenType = builder.getTokenType(); } PsiBuilder.Marker expr = null; if (tokenType == JavaTokenType.LT) { expr = builder.mark(); if (!myParser.getReferenceParser().parseReferenceParameterList(builder, false, false)) { expr.rollbackTo(); return null; } tokenType = builder.getTokenType(); if (!THIS_OR_SUPER.contains(tokenType)) { expr.rollbackTo(); return null; } } if (THIS_OR_SUPER.contains(tokenType)) { if (expr == null) { expr = builder.mark(); builder.mark().done(JavaElementType.REFERENCE_PARAMETER_LIST); } builder.advanceLexer(); expr.done( builder.getTokenType() == JavaTokenType.LPARENTH ? JavaElementType.REFERENCE_EXPRESSION : tokenType == JavaTokenType.THIS_KEYWORD ? JavaElementType.THIS_EXPRESSION : JavaElementType.SUPER_EXPRESSION); return expr; } return null; }
/** * Parses tokens as variables name; replaces: * * @param b PerlBuilder * @param l parsing level * @return parsing result */ public static boolean parseVariableName(PsiBuilder b, int l) { IElementType currentTokenType = b.getTokenType(); IElementType nextTokenType = b.rawLookup(1); PsiBuilder.Marker m; // while (currentTokenType == SIGIL_SCALAR // sigil is here // && POST_SIGILS_SUFFIXES.contains(nextTokenType) // next can be variable name // ) // { // if (m == null) // m = b.mark(); // b.advanceLexer(); // currentTokenType = nextTokenType; // nextTokenType = b.rawLookup(1); // } // // if (m != null) // m.collapse(SCALAR_SIGILS); // checking for scalar cast if (currentTokenType == SIGIL_SCALAR && POST_SIGILS_SUFFIXES.contains(b.lookAhead(1))) return false; // $package:: // $package::var if (PACKAGE_TOKENS.contains(currentTokenType)) { PsiBuilder.Marker mp = b.mark(); b.advanceLexer(); mp.collapse(PACKAGE); if (CONVERTABLE_TOKENS.contains(nextTokenType)) { PsiBuilder.Marker mv = b.mark(); b.advanceLexer(); mv.collapse(VARIABLE_NAME); } return true; } // $var else if (POSSIBLE_VARIABLE_NAME.contains(currentTokenType)) { if (currentTokenType == OPERATOR_BITWISE_XOR && CONTROL_VARIABLE_NAMES.contains(nextTokenType)) // branch for $^] { m = b.mark(); b.advanceLexer(); b.advanceLexer(); m.collapse(VARIABLE_NAME); } else { PsiBuilder.Marker mv = b.mark(); b.advanceLexer(); mv.collapse(VARIABLE_NAME); } return true; } // ${var} else if (currentTokenType == LEFT_BRACE) { b.advanceLexer(); currentTokenType = nextTokenType; nextTokenType = b.lookAhead(1); // ${package::} // ${package::var} if (PACKAGE_TOKENS.contains(currentTokenType)) { PsiBuilder.Marker mp = b.mark(); b.advanceLexer(); mp.collapse(PACKAGE); if (CONVERTABLE_TOKENS.contains(nextTokenType) && b.lookAhead(1) == RIGHT_BRACE) { PsiBuilder.Marker mv = b.mark(); b.advanceLexer(); mv.collapse(VARIABLE_NAME); b.advanceLexer(); return true; } else if (nextTokenType == RIGHT_BRACE) { b.advanceLexer(); return true; } } // ${var} else if (POSSIBLE_VARIABLE_NAME.contains(currentTokenType) && nextTokenType == RIGHT_BRACE) { PsiBuilder.Marker mv = b.mark(); b.advanceLexer(); mv.collapse(VARIABLE_NAME); b.advanceLexer(); return true; } } return false; }
/** * Parses invocable method As input we may have: PACKAGE_IDENTIFIER IDENTIFIER Foo::sub IDENTIFIER * PACKAGE_IDENTIFIER sub Foo:: IDENTIFIER IDENTIFIER sub Foo * * @param b PerlBuilder * @param l parsing level * @return parsing result */ public static boolean parseMethod(PsiBuilder b, int l) { IElementType currentTokenType = b.getTokenType(); IElementType nextTokenType = b.lookAhead(1); assert b instanceof PerlBuilder; // can be // Foo::method // Foo::Bar if (PACKAGE_TOKENS.contains(currentTokenType) && CONVERTABLE_TOKENS.contains(nextTokenType)) { PerlTokenData nextTokenData = ((PerlBuilder) b).lookupToken(1); PerlTokenData nextNextTokenData = ((PerlBuilder) b).lookupToken(2); IElementType nextNextTokenType = nextNextTokenData == null ? null : nextNextTokenData.getTokenType(); String canonicalPackageName = PerlPackageUtil.getCanonicalPackageName(b.getTokenText()); String potentialSubName = canonicalPackageName + "::" + nextTokenData.getTokenText(); if (nextNextTokenType == LEFT_PAREN // Package::Identifier( - what can it be? || ((PerlBuilder) b).isKnownSub(potentialSubName) // we know this sub || !((PerlBuilder) b).isKnownPackage(potentialSubName)) // we don't know such package return convertPackageIdentifier(b, l) && convertIdentifier(b, l, SUB); else return false; } // method else if (CONVERTABLE_TOKENS.contains(currentTokenType)) { PerlTokenData prevTokenData = ((PerlBuilder) b).lookupToken(-1); // ->sub if (prevTokenData != null && prevTokenData.getTokenType() == OPERATOR_DEREFERENCE) return convertIdentifier(b, l, SUB); // may be // method Foo:: // method Foo::Bar // method Foo::othermethod else if (PACKAGE_TOKENS.contains(nextTokenType)) { IElementType nextNextTokenType = b.lookAhead(2); // sub Foo::->method if (nextNextTokenType == OPERATOR_DEREFERENCE) return convertIdentifier(b, l, SUB); // identifier Package::identifier else if (CONVERTABLE_TOKENS.contains(nextNextTokenType)) { // identifier Package::identifier-> if (b.lookAhead(3) == OPERATOR_DEREFERENCE) return convertIdentifier(b, l, SUB); PerlTokenData nextTokenData = ((PerlBuilder) b).lookupToken(1); PerlTokenData nextNextTokenData = ((PerlBuilder) b).lookupToken(2); String packageOrSub = PerlPackageUtil.getCanonicalPackageName(nextTokenData.getTokenText()) + "::" + nextNextTokenData.getTokenText(); if (((PerlBuilder) b).isKnownSub(packageOrSub)) return convertIdentifier(b, l, SUB); else if (((PerlBuilder) b).isKnownPackage(packageOrSub)) return convertIdentifier(b, l, SUB) && mergePackageName(b, l); return convertIdentifier(b, l, SUB); } else // it's method Package:: return convertIdentifier(b, l, SUB) && convertPackageIdentifier(b, l); } // may be // method Foo else if (CONVERTABLE_TOKENS.contains(nextTokenType) && b.lookAhead(2) != OPERATOR_DEREFERENCE) { PerlTokenData nextTokenData = ((PerlBuilder) b).lookupToken(1); String potentialSubName = nextTokenData.getTokenText() + "::" + b.getTokenText(); if (((PerlBuilder) b).isKnownSub(potentialSubName)) return convertIdentifier(b, l, SUB) && convertIdentifier(b, l, PACKAGE); else return convertIdentifier(b, l, SUB); } // KnownPackage-> else if (nextTokenType == OPERATOR_DEREFERENCE && ((PerlBuilder) b).isKnownPackage(b.getTokenText())) return false; // it's just sub else return convertIdentifier(b, l, SUB); } return false; }
public static boolean mergeRequirePackageName(PsiBuilder b, int l) { if (CONVERTABLE_TOKENS.contains(b.getTokenType()) && b.lookAhead(1) == LEFT_PAREN) return false; return mergePackageName(b, l); }