public IElementType parseProperty(boolean local) { if (at(VAL_KEYWORD) || at(VAR_KEYWORD)) { advance(); // VAL_KEYWORD or VAR_KEYWORD } else { errorAndAdvance("Expecting 'val' or 'var'"); } boolean typeParametersDeclared = at(LT) && parseTypeParameterList(TokenSet.create(IDENTIFIER, EQ, COLON, SEMICOLON)); TokenSet propertyNameFollow = TokenSet.create( COLON, EQ, LBRACE, RBRACE, SEMICOLON, VAL_KEYWORD, VAR_KEYWORD, FUN_KEYWORD, CLASS_KEYWORD); myBuilder.disableJoiningComplexTokens(); // TODO: extract constant int lastDot = matchTokenStreamPredicate( new LastBefore( new AtSet(DOT, SAFE_ACCESS), new AbstractTokenStreamPredicate() { @Override public boolean matching(boolean topLevel) { if (topLevel && (at(EQ) || at(COLON))) return true; if (topLevel && at(IDENTIFIER)) { IElementType lookahead = lookahead(1); return lookahead != LT && lookahead != DOT && lookahead != SAFE_ACCESS && lookahead != QUEST; } return false; } })); PsiBuilder.Marker receiver = mark(); parseReceiverType("property", propertyNameFollow, lastDot); boolean multiDeclaration = at(LPAR); boolean receiverTypeDeclared = lastDot != -1; errorIf( receiver, multiDeclaration && receiverTypeDeclared, "Receiver type is not allowed on a multi-declaration"); if (multiDeclaration) { PsiBuilder.Marker multiDecl = mark(); parseMultiDeclarationName(propertyNameFollow); errorIf(multiDecl, !local, "Multi-declarations are only allowed for local variables/values"); } else { parseFunctionOrPropertyName(receiverTypeDeclared, "property", propertyNameFollow); } myBuilder.restoreJoiningComplexTokensState(); if (at(COLON)) { PsiBuilder.Marker type = mark(); advance(); // COLON if (!parseIdeTemplate()) { parseTypeRef(); } errorIf(type, multiDeclaration, "Type annotations are not allowed on multi-declarations"); } parseTypeConstraintsGuarded(typeParametersDeclared); if (local) { if (at(BY_KEYWORD)) { parsePropertyDelegate(); } else if (at(EQ)) { advance(); // EQ myExpressionParsing.parseExpression(); // "val a = 1; b" must not be an infix call of b on "val ...;" } } else { if (at(BY_KEYWORD)) { parsePropertyDelegate(); consumeIf(SEMICOLON); } else if (at(EQ)) { advance(); // EQ myExpressionParsing.parseExpression(); consumeIf(SEMICOLON); } if (parsePropertyGetterOrSetter()) { parsePropertyGetterOrSetter(); } if (!atSet(EOL_OR_SEMICOLON, RBRACE)) { if (getLastToken() != SEMICOLON) { errorUntil("Property getter or setter expected", TokenSet.create(EOL_OR_SEMICOLON)); } } else { consumeIf(SEMICOLON); } } return multiDeclaration ? MULTI_VARIABLE_DECLARATION : PROPERTY; }
/* * function * : modifiers "fun" typeParameters? * (type "." | attributes)? * SimpleName * typeParameters? functionParameters (":" type)? * typeConstraints * functionBody? * ; */ IElementType parseFunction() { assert _at(FUN_KEYWORD); advance(); // FUN_KEYWORD // Recovery for the case of class A { fun| } if (at(RBRACE)) { error("Function body expected"); return FUN; } boolean typeParameterListOccurred = false; if (at(LT)) { parseTypeParameterList(TokenSet.create(LBRACKET, LBRACE, LPAR)); typeParameterListOccurred = true; } myBuilder.disableJoiningComplexTokens(); int lastDot = findLastBefore(RECEIVER_TYPE_TERMINATORS, TokenSet.create(LPAR), true); TokenSet functionNameFollow = TokenSet.create(LT, LPAR, COLON, EQ); parseReceiverType("function", functionNameFollow, lastDot); parseFunctionOrPropertyName(lastDot != -1, "function", functionNameFollow); myBuilder.restoreJoiningComplexTokensState(); TokenSet valueParametersFollow = TokenSet.create(COLON, EQ, LBRACE, SEMICOLON, RPAR); if (at(LT)) { PsiBuilder.Marker error = mark(); parseTypeParameterList(TokenSet.orSet(TokenSet.create(LPAR), valueParametersFollow)); errorIf( error, typeParameterListOccurred, "Only one type parameter list is allowed for a function"); typeParameterListOccurred = true; } if (at(LPAR)) { parseValueParameterList(false, valueParametersFollow); } else { error("Expecting '('"); } if (at(COLON)) { advance(); // COLON if (!parseIdeTemplate()) { parseTypeRef(); } } parseTypeConstraintsGuarded(typeParameterListOccurred); if (at(SEMICOLON)) { advance(); // SEMICOLON } else if (at(EQ) || at(LBRACE)) { parseFunctionBody(); } return FUN; }