//===--- ParseDecl.cpp - Swift Language Parser for Declarations -----------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // Declaration Parsing and AST Building // //===----------------------------------------------------------------------===// #include "swift/Parse/Lexer.h" #include "Parser.h" #include "swift/Subsystems.h" #include "swift/AST/Attr.h" #include "swift/AST/Diagnostics.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PathV2.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" using namespace swift; Identifier Parser::getModuleIdentifier() { StringRef moduleName = Buffer->getBufferIdentifier(); // As a special case, recognize . if (moduleName == "") return Context.getIdentifier("stdin"); // Find the stem of the filename. moduleName = llvm::sys::path::stem(moduleName); // Complain about non-identifier characters in the module name. if (!Lexer::isIdentifier(moduleName)) { diagnose(L.getLocForStartOfBuffer(), diag::bad_module_name); moduleName = "bad"; } return Context.getIdentifier(moduleName); } /// parseTranslationUnit - Main entrypoint for the parser. /// translation-unit: /// stmt-brace-item* TranslationUnit *Parser::parseTranslationUnit() { // Prime the lexer. consumeToken(); SourceLoc FileStartLoc = Tok.getLoc(); TranslationUnit *TU = new (Context) TranslationUnit(getModuleIdentifier(), Component, Context, IsMainModule); CurDeclContext = TU; // Parse the body of the file. SmallVector Items; parseBraceItemList(Items, true); // Process the end of the translation unit. SourceLoc FileEnd = Tok.getLoc(); // First thing, we transform the body into a brace expression. TU->Body = BraceStmt::create(Context, FileStartLoc, Items, FileEnd); TU->setUnresolvedIdentifierTypes( Context.AllocateCopy(llvm::makeArrayRef(UnresolvedIdentifierTypes))); UnresolvedIdentifierTypes.clear(); // Note that the translation unit is fully parsed and verify it. TU->ASTStage = TranslationUnit::Parsed; verify(TU); return TU; } namespace { #define MAKE_ENUMERATOR(id) id, enum class AttrName { none, #define ATTR(X) X, #include "swift/AST/Attr.def" }; } static AttrName getAttrName(StringRef text) { return llvm::StringSwitch(text) #define ATTR(X) .Case(#X, AttrName::X) #include "swift/AST/Attr.def" .Default(AttrName::none); } static Associativity getAssociativity(AttrName attr) { switch (attr) { case AttrName::infix: return Associativity::None; case AttrName::infix_left: return Associativity::Left; case AttrName::infix_right: return Associativity::Right; default: llvm_unreachable("bad associativity"); } } static Resilience getResilience(AttrName attr) { switch (attr) { case AttrName::resilient: return Resilience::Resilient; case AttrName::fragile: return Resilience::Fragile; case AttrName::born_fragile: return Resilience::InherentlyFragile; default: llvm_unreachable("bad resilience"); } } /// parseAttribute /// attribute: /// 'infix' '=' numeric_constant /// 'infix_left' '=' numeric_constant /// 'infix_right' '=' numeric_constant /// 'unary' bool Parser::parseAttribute(DeclAttributes &Attributes) { if (!Tok.is(tok::identifier)) { diagnose(Tok, diag::expected_attribute_name); skipUntil(tok::r_square); return true; } switch (AttrName attr = getAttrName(Tok.getText())) { case AttrName::none: diagnose(Tok, diag::unknown_attribute, Tok.getText()); skipUntil(tok::r_square); return true; // Infix attributes. case AttrName::infix: case AttrName::infix_left: case AttrName::infix_right: { if (Attributes.isInfix()) diagnose(Tok, diag::duplicate_attribute, Tok.getText()); consumeToken(tok::identifier); Associativity Assoc = getAssociativity(attr); // The default precedence is 100. Attributes.Infix = InfixData(100, Assoc); if (consumeIf(tok::equal)) { SourceLoc PrecLoc = Tok.getLoc(); StringRef Text = Tok.getText(); if (!parseToken(tok::integer_literal, diag::expected_precedence_value)){ long long Value; if (Text.getAsInteger(10, Value) || Value > 255 || Value < 0) diagnose(PrecLoc, diag::invalid_precedence, Text); else Attributes.Infix = InfixData(Value, Assoc); } else { // FIXME: I'd far rather that we describe this in terms of some // list structure in the caller. This feels too ad hoc. skipUntil(tok::r_square, tok::comma); } } return false; } // Resilience attributes. case AttrName::resilient: case AttrName::fragile: case AttrName::born_fragile: { if (Attributes.Resilience.isValid()) diagnose(Tok, diag::duplicate_attribute, Tok.getText()); consumeToken(tok::identifier); Resilience resil = getResilience(attr); // TODO: 'fragile' should allow deployment versioning. Attributes.Resilience = ResilienceData(resil); return false; } // 'byref' attribute. // FIXME: only permit this in specific contexts. case AttrName::byref: { SourceLoc TokLoc = Tok.getLoc(); if (Attributes.Byref) diagnose(Tok, diag::duplicate_attribute, Tok.getText()); consumeToken(tok::identifier); Attributes.Byref = true; Attributes.ByrefImplicit = false; Attributes.ByrefHeap = false; // Permit "qualifiers" on the byref. SourceLoc beginLoc = Tok.getLoc(); if (consumeIf(tok::l_paren) || consumeIf(tok::l_paren_space)) { if (!Tok.is(tok::identifier)) { diagnose(Tok, diag::byref_attribute_expected_identifier); skipUntil(tok::r_paren); } else if (Tok.getText() == "implicit") { Attributes.ByrefImplicit = true; consumeToken(tok::identifier); } else if (Tok.getText() == "heap") { Attributes.ByrefHeap = true; consumeToken(tok::identifier); } else { diagnose(Tok, diag::byref_attribute_unknown_qualifier); consumeToken(tok::identifier); } SourceLoc endLoc; parseMatchingToken(tok::r_paren, endLoc, diag::byref_attribute_expected_rparen, beginLoc, diag::opening_paren); } // Verify that we're not combining this attribute incorrectly. Cannot be // both byref and auto_closure. if (Attributes.isAutoClosure()) { diagnose(TokLoc, diag::cannot_combine_attribute, "auto_closure"); Attributes.AutoClosure = false; } return false; } // FIXME: Only valid on var and tuple elements, not on func's, typealias, etc. case AttrName::auto_closure: { SourceLoc TokLoc = Tok.getLoc(); if (Attributes.isAutoClosure()) diagnose(Tok, diag::duplicate_attribute, Tok.getText()); consumeToken(tok::identifier); // Verify that we're not combining this attribute incorrectly. Cannot be // both byref and auto_closure. if (Attributes.isByref()) { diagnose(TokLoc, diag::cannot_combine_attribute, "byref"); return false; } Attributes.AutoClosure = true; return false; } } llvm_unreachable("bad attribute kind"); } /// parsePresentAttributeList - This is the internal implementation of /// parseAttributeList, which we expect to be inlined to handle the common case /// of an absent attribute list. /// attribute-list: /// /*empty*/ /// '[' ']' /// '[' attribute (',' attribute)* ']' void Parser::parseAttributeListPresent(DeclAttributes &Attributes) { Attributes.LSquareLoc = consumeToken(tok::l_square); // If this is an empty attribute list, consume it and return. if (Tok.is(tok::r_square)) { Attributes.RSquareLoc = consumeToken(tok::r_square); return; } bool HadError = parseAttribute(Attributes); while (Tok.is(tok::comma)) { consumeToken(tok::comma); HadError |= parseAttribute(Attributes); } Attributes.RSquareLoc = Tok.getLoc(); if (consumeIf(tok::r_square)) return; // Otherwise, there was an error parsing the attribute list. If we already // reported an error, skip to a ], otherwise report the error. if (!HadError) parseMatchingToken(tok::r_square, Attributes.RSquareLoc, diag::expected_in_attribute_list, Attributes.LSquareLoc, diag::opening_bracket); skipUntil(tok::r_square); consumeIf(tok::r_square); } /// parseDecl - Parse a single syntactic declaration and return a list of decl /// ASTs. This can return multiple results for var decls that bind to multiple /// values, structs that define a struct decl and a constructor, etc. /// /// This method returns true on a parser error that requires recovery. /// /// decl: /// decl-typealias /// decl-extension /// decl-var /// decl-func /// decl-oneof /// decl-struct /// decl-import /// bool Parser::parseDecl(SmallVectorImpl &Entries, unsigned Flags) { unsigned EntryStart = Entries.size(); bool HadParseError = false; switch (Tok.getKind()) { default: ParseError: diagnose(Tok, diag::expected_decl); HadParseError = true; break; case tok::kw_import: Entries.push_back(parseDeclImport()); break; case tok::kw_extension: Entries.push_back(parseDeclExtension()); break; case tok::kw_var: HadParseError = parseDeclVar(Flags & PD_HasContainerType, Entries); break; case tok::kw_typealias: Entries.push_back(parseDeclTypeAlias()); break; case tok::kw_oneof: HadParseError = parseDeclOneOf(Entries); break; case tok::kw_struct: HadParseError = parseDeclStruct(Entries); break; case tok::kw_protocol: Entries.push_back(parseDeclProtocol()); break; case tok::kw_static: if (peekToken().isNot(tok::kw_func)) goto ParseError; // FALL THROUGH. case tok::kw_func: Entries.push_back(parseDeclFunc(Flags & PD_HasContainerType)); break; } // If we got back a null pointer, then a parse error happened. if (Entries.back() == 0) { Entries.pop_back(); HadParseError = true; } // Validate the new entries. for (unsigned i = EntryStart, e = Entries.size(); i != e; ++i) { Decl *D = Entries[i]; // FIXME: Mark decls erroneous. if (isa(D) && !(Flags & PD_AllowTopLevel)) diagnose(D->getLocStart(), diag::decl_inner_scope); if (isa(D) && (Flags & PD_DisallowVar) && !cast(D)->isProperty()) { diagnose(D->getLocStart(), diag::disallowed_var_decl); } else if (NamedDecl *ND = dyn_cast(D)) { if (ND->isOperator() && (Flags & PD_DisallowOperators)) diagnose(ND->getLocStart(), diag::operator_in_decl); } } return HadParseError; } /// parseDeclImport - Parse an 'import' declaration, returning null (and doing /// no token skipping) on error. /// /// decl-import: /// 'import' attribute-list any-identifier ('.' any-identifier)* /// Decl *Parser::parseDeclImport() { SourceLoc ImportLoc = consumeToken(tok::kw_import); DeclAttributes Attributes; parseAttributeList(Attributes); SmallVector, 8> ImportPath(1); ImportPath.back().second = Tok.getLoc(); if (parseAnyIdentifier(ImportPath.back().first, diag::decl_expected_module_name)) return 0; while (consumeIf(tok::period)) { ImportPath.push_back(std::make_pair(Identifier(), Tok.getLoc())); if (parseAnyIdentifier(ImportPath.back().first, diag::expected_identifier_in_decl, "import")) return 0; } if (!Attributes.empty()) diagnose(Attributes.LSquareLoc, diag::import_attributes); return ImportDecl::create(Context, CurDeclContext, ImportLoc, ImportPath); } /// parseDeclExtension - Parse an 'extension' declaration. /// extension: /// 'extension' type-identifier '{' decl* '}' /// Decl *Parser::parseDeclExtension() { SourceLoc ExtensionLoc = consumeToken(tok::kw_extension); Type Ty; SourceLoc LBLoc, RBLoc; if (parseTypeIdentifier(Ty) || parseToken(tok::l_brace, LBLoc, diag::expected_lbrace_oneof_type)) return 0; // Parse the body as a series of decls. SmallVector MemberDecls; while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { if (parseDecl(MemberDecls, PD_HasContainerType|PD_DisallowVar|PD_DisallowOperators)) skipUntilDeclRBrace(); } parseMatchingToken(tok::r_brace, RBLoc, diag::expected_rbrace_extension, LBLoc, diag::opening_brace); return actOnDeclExtension(ExtensionLoc, Ty, MemberDecls); } /// actOnDeclExtension - Given a list of declarations in an 'extension', /// 'struct', 'oneof', etc, create an ExtensionDecl and register them as /// members. Decl *Parser::actOnDeclExtension(SourceLoc ExtensionLoc, Type Ty, ArrayRef MemberDecls) { ExtensionDecl *ED = new (Context) ExtensionDecl(ExtensionLoc, Ty, Context.AllocateCopy(MemberDecls), CurDeclContext); // Install all of the members into the Extension's DeclContext. for (Decl *D : MemberDecls) D->setDeclContext(ED); return ED; } /// parseDeclTypeAlias /// decl-typealias: /// 'typealias' identifier ':' type TypeAliasDecl *Parser::parseDeclTypeAlias() { SourceLoc TypeAliasLoc = consumeToken(tok::kw_typealias); Identifier Id; Type Ty; if (parseIdentifier(Id, diag::expected_identifier_in_decl, "typealias") || parseToken(tok::colon, diag::expected_colon_in_typealias) || parseType(Ty, diag::expected_type_in_typealias)) return 0; TypeAliasDecl *TAD = new (Context) TypeAliasDecl(TypeAliasLoc, Id, Ty, CurDeclContext, ScopeInfo.isModuleScope()); ScopeInfo.addToScope(TAD); return TAD; } static void addVarsToScope(Parser &P, Pattern *Pat, SmallVectorImpl &Decls, DeclAttributes &Attributes) { switch (Pat->getKind()) { // Recurse into patterns. case PatternKind::Tuple: for (auto &field : cast(Pat)->getFields()) addVarsToScope(P, field.getPattern(), Decls, Attributes); return; case PatternKind::Paren: return addVarsToScope(P, cast(Pat)->getSubPattern(), Decls, Attributes); case PatternKind::Typed: return addVarsToScope(P, cast(Pat)->getSubPattern(), Decls, Attributes); // Handle vars. case PatternKind::Named: { VarDecl *VD = cast(Pat)->getDecl(); VD->setDeclContext(P.CurDeclContext); VD->setModuleScope(P.ScopeInfo.isModuleScope()); if (!VD->hasType()) VD->setType(UnstructuredDependentType::get(P.Context)); if (Attributes.isValid()) VD->getMutableAttrs() = Attributes; Decls.push_back(VD); P.ScopeInfo.addToScope(VD); return; } // Handle non-vars. case PatternKind::Any: return; } llvm_unreachable("bad pattern kind!"); } /// parseDeclVarGetSet - Parse the brace-enclosed getter and setter for a variable. /// /// decl-var: /// 'var' attribute-list identifier : type-annotation { var-get-set } /// var-get-set: /// var-get var-set? /// var-set var-get /// /// var-get: /// 'get' stmt-brace /// /// var-set: /// 'set' var-set-name? stmt-brace /// /// var-set-name: /// '(' identifier ')' void Parser::parseDeclVarGetSet(Pattern &pattern, bool hasContainerType) { assert(!GetIdent.empty() && "No 'get' identifier?"); assert(!SetIdent.empty() && "No 'set' identifier?"); bool Invalid = false; // The grammar syntactically requires a simple identifier for the variable // name. Complain if that isn't what we got. VarDecl *PrimaryVar = 0; { Pattern *PrimaryPattern = &pattern; if (TypedPattern *Typed = dyn_cast(PrimaryPattern)) PrimaryPattern = Typed->getSubPattern(); if (NamedPattern *Named = dyn_cast(PrimaryPattern)) { PrimaryVar = Named->getDecl(); } } if (!PrimaryVar) diagnose(pattern.getLoc(), diag::getset_nontrivial_pattern); // The grammar syntactically requires a type annotation. Complain if // our pattern does not have one. Type Ty; if (pattern.hasType()) Ty = pattern.getType(); else { if (PrimaryVar) diagnose(pattern.getLoc(), diag::getset_missing_type); Ty = ErrorType::get(Context); } SourceLoc LBLoc = consumeToken(tok::l_brace); // Parse getter and setter. FuncDecl *Get = 0; FuncDecl *Set = 0; SourceLoc LastValidLoc = LBLoc; while (true) { if (!Tok.is(tok::identifier)) break; Identifier Id = Context.getIdentifier(Tok.getText()); if (Id == GetIdent) { // var-get ::= 'get' stmt-brace // Have we already parsed a var-get clause? if (Get) { if (PrimaryVar) { diagnose(Tok.getLoc(), diag::duplicate_getset, false, PrimaryVar->getName()); diagnose(Get->getLocStart(), diag::previous_getset, false); } // Forget the previous version. Get = 0; } SourceLoc GetLoc = consumeToken(); // It's easy to imagine someone writing redundant parentheses here; // diagnose this directly. if ((Tok.is(tok::l_paren) || Tok.is(tok::l_paren_space)) && peekToken().is(tok::r_paren)) { SourceLoc StartLoc = consumeToken(); SourceLoc EndLoc = consumeToken(); diagnose(StartLoc, diag::empty_parens_getsetname, false) << SourceRange(StartLoc, EndLoc); } // Set up a function declaration for the getter and parse its body. // Create the parameter list(s) for the getter. llvm::SmallVector Params; // Add the implicit 'this' to Params, if needed. if (hasContainerType) Params.push_back(buildImplicitThisParameter()); // Add a no-parameters clause. Params.push_back(TuplePattern::create(Context, SourceLoc(), ArrayRef(), SourceLoc())); // Getter has type: () -> T. Type FuncTy = Ty; if (buildFunctionSignature(Params, FuncTy)) { skipUntilDeclRBrace(); Invalid = true; break; } Scope FnBodyScope(this); // Start the function. FuncExpr *GetFn = actOnFuncExprStart(GetLoc, FuncTy, Params); // Establish the new context. ContextChange CC(*this, GetFn); NullablePtr Body = parseStmtBrace(diag::expected_lbrace_get); if (Body.isNull()) { GetLoc = SourceLoc(); skipUntilDeclRBrace(); Invalid = true; break; } GetFn->setBody(Body.get()); LastValidLoc = Body.get()->getRBraceLoc(); Get = new (Context) FuncDecl(/*StaticLoc=*/SourceLoc(), GetLoc, Identifier(), FuncTy, GetFn, CurDeclContext, ScopeInfo.isModuleScope()); continue; } if (Id != SetIdent) { diagnose(Tok.getLoc(), diag::expected_getset); skipUntilDeclRBrace(); Invalid = true; break; } // var-set ::= 'set' var-set-name? stmt-brace // Have we already parsed a var-set clause? if (Set) { if (PrimaryVar) { diagnose(Tok.getLoc(), diag::duplicate_getset, true, PrimaryVar->getName()); diagnose(Set->getLocStart(), diag::previous_getset, true); } // Forget the previous setter. Set = 0; } SourceLoc SetLoc = consumeToken(); // var-set-name ::= '(' identifier ')' Identifier SetName; SourceLoc SetNameLoc; SourceRange SetNameParens; if (Tok.is(tok::l_paren) || Tok.is(tok::l_paren_space)) { SourceLoc StartLoc = consumeToken(); if (Tok.is(tok::identifier)) { // We have a name. SetName = Context.getIdentifier(Tok.getText()); SetNameLoc = consumeToken(); // Look for the closing ')'. SourceLoc EndLoc; if (parseMatchingToken(tok::r_paren, EndLoc, diag::expected_rparen_setname, StartLoc, diag::opening_paren)) EndLoc = SetNameLoc; SetNameParens = SourceRange(StartLoc, EndLoc); } else if (Tok.is(tok::r_paren)) { diagnose(StartLoc, diag::empty_parens_getsetname, true) << SourceRange(StartLoc, consumeToken()); } else { diagnose(Tok.getLoc(), diag::expected_setname); skipUntil(tok::r_paren, tok::l_brace); if (Tok.is(tok::r_paren)) consumeToken(); } } // Set up a function declaration for the setter and parse its body. // Create the parameter list(s) for the setter. llvm::SmallVector Params; // Add the implicit 'this' to Params, if needed. if (hasContainerType) Params.push_back(buildImplicitThisParameter()); // Add the parameter. If no name was specified, the name defaults to // 'value'. if (SetName.empty()) SetName = Context.getIdentifier("value"); { VarDecl *Value = new (Context) VarDecl(SetNameLoc, SetName, Ty, CurDeclContext, ScopeInfo.isModuleScope()); Pattern *ValuePattern = new (Context) TypedPattern(new (Context) NamedPattern(Value), Ty); TuplePatternElt ValuePatternElt(ValuePattern, /*Init=*/nullptr); Pattern *ValueParamsPattern = TuplePattern::create(Context, SetNameParens.Start, ArrayRef(&ValuePatternElt, 1), SetNameParens.End); Params.push_back(ValueParamsPattern); } // Getter has type: (value : T) -> () Type FuncTy = TupleType::getEmpty(Context); if (buildFunctionSignature(Params, FuncTy)) { skipUntilDeclRBrace(); Invalid = true; break; } Scope FnBodyScope(this); // Start the function. FuncExpr *SetFn = actOnFuncExprStart(SetLoc, FuncTy, Params); // Establish the new context. ContextChange CC(*this, SetFn); // Parse the body. NullablePtr Body = parseStmtBrace(diag::expected_lbrace_set); if (Body.isNull()) { skipUntilDeclRBrace(); Invalid = true; break; } SetFn->setBody(Body.get()); LastValidLoc = Body.get()->getRBraceLoc(); Set = new (Context) FuncDecl(/*StaticLoc=*/SourceLoc(), SetLoc, Identifier(), FuncTy, SetFn, CurDeclContext, ScopeInfo.isModuleScope()); } // Parse the final '}'. SourceLoc RBLoc; if (Invalid) { skipUntilDeclRBrace(); RBLoc = LastValidLoc; } else if (parseMatchingToken(tok::r_brace, RBLoc, diag::expected_rbrace_in_getset, LBLoc, diag::opening_brace)) { RBLoc = LastValidLoc; } if (Set && !Get) { if (!Invalid) diagnose(Set->getLocStart(), diag::var_set_without_get); Set = nullptr; Invalid = true; } // If things went well, turn this variable into a property. if (!Invalid && PrimaryVar && (Set || Get)) PrimaryVar->setProperty(Context, LBLoc, Get, Set, RBLoc); } /// parseDeclVar - Parse a 'var' declaration, returning null (and doing no /// token skipping) on error. /// /// decl-var: /// 'var' attribute-list pattern initializer? /// 'var' attribute-list identifier : type-annotation { var-get-set } bool Parser::parseDeclVar(bool hasContainerType, SmallVectorImpl &Decls){ SourceLoc VarLoc = consumeToken(tok::kw_var); DeclAttributes Attributes; parseAttributeList(Attributes); NullablePtr pattern = parsePattern(); if (pattern.isNull()) return true; // If we syntactically match the second decl-var production, with a // var-get-set clause, parse the var-get-set clause. bool HasGetSet = false; if (Tok.is(tok::l_brace)) { // Check whether the next token is 'get' or 'set'. const Token &NextTok = peekToken(); if (NextTok.is(tok::identifier)) { Identifier Name = Context.getIdentifier(NextTok.getText()); // Get the identifiers for both 'get' and 'set'. if (GetIdent.empty()) { GetIdent = Context.getIdentifier("get"); SetIdent = Context.getIdentifier("set"); } if (Name == GetIdent || Name == SetIdent) { parseDeclVarGetSet(*pattern.get(), hasContainerType); HasGetSet = true; } } } Type Ty; NullablePtr Init; if (consumeIf(tok::equal)) { Init = parseExpr(diag::expected_initializer_expr); if (Init.isNull()) return true; if (HasGetSet) { diagnose(pattern.get()->getLoc(), diag::getset_init) << Init.get()->getSourceRange(); Init = nullptr; } } addVarsToScope(*this, pattern.get(), Decls, Attributes); PatternBindingDecl *PBD = new (Context) PatternBindingDecl(VarLoc, pattern.get(), Init.getPtrOrNull(), CurDeclContext); Decls.push_back(PBD); return false; } /// parseDeclVarSimple - This just parses a reduced case of decl-var. /// FIXME: This is only used by protocol elements. It seems that there should /// be a better way to handle these. /// /// decl-var-simple: /// 'var' identifier ':' type-annotation /// VarDecl *Parser::parseDeclVarSimple() { SourceLoc VarLoc = consumeToken(tok::kw_var); if (Tok.isNot(tok::identifier)) diagnose(Tok, diag::expected_lparen_var_name); Identifier ident = Context.getIdentifier(Tok.getText()); consumeToken(); if (!consumeIf(tok::colon)) { diagnose(Tok, diag::expected_type_or_init); return 0; } Type Ty; if (parseTypeAnnotation(Ty, diag::expected_type)) return 0; return new (Context) VarDecl(VarLoc, ident, Ty, CurDeclContext, ScopeInfo.isModuleScope()); } /// addImplicitThisParameter - Add an implicit 'this' parameter to the given /// set of parameter clauses. Pattern *Parser::buildImplicitThisParameter() { VarDecl *D = new (Context) VarDecl(SourceLoc(), Context.getIdentifier("this"), Type(), CurDeclContext, /*isModuleScope*/false); Pattern *P = new (Context) NamedPattern(D); return new (Context) TypedPattern(P, UnstructuredDependentType::get(Context)); } /// parseDeclFunc - Parse a 'func' declaration, returning null on error. The /// caller handles this case and does recovery as appropriate. If AllowScoped /// is true, we parse both productions. /// /// decl-func: /// 'static'? 'func' attribute-list any-identifier func-signature /// stmt-brace? /// /// NOTE: The caller of this method must ensure that the token sequence is /// either 'func' or 'static' 'func'. /// FuncDecl *Parser::parseDeclFunc(bool hasContainerType) { SourceLoc StaticLoc; if (Tok.is(tok::kw_static)) { StaticLoc = consumeToken(tok::kw_static); // Reject 'static' functions at global scope. if (!hasContainerType) { diagnose(Tok, diag::static_func_decl_global_scope); StaticLoc = SourceLoc(); } } SourceLoc FuncLoc = consumeToken(tok::kw_func); DeclAttributes Attributes; // FIXME: Implicitly add immutable attribute. parseAttributeList(Attributes); Identifier Name; if (parseAnyIdentifier(Name, diag::expected_identifier_in_decl, "func")) return 0; // We force first type of a func declaration to be a tuple for consistency. if (Tok.isNot(tok::l_paren) && Tok.isNot(tok::l_paren_space)) { diagnose(Tok, diag::func_decl_without_paren); return 0; } SmallVector Params; // If we're within a container and this isn't a static method, add an // implicit first pattern to match the container type as an element // named 'this'. This turns "(int)->int" on FooTy into "(this : // [byref] FooTy)->((int)->int)". Note that we can't actually compute the // type here until Sema. if (hasContainerType && !StaticLoc.isValid()) Params.push_back(buildImplicitThisParameter()); Type FuncTy; if (parseFunctionSignature(Params, FuncTy)) return 0; // Enter the arguments for the function into a new function-body scope. We // need this even if there is no function body to detect argument name // duplication. FuncExpr *FE = 0; { Scope FnBodyScope(this); FE = actOnFuncExprStart(FuncLoc, FuncTy, Params); // Establish the new context. ContextChange CC(*this, FE); // Then parse the expression. NullablePtr Body; // Check to see if we have a "{" to start a brace statement. if (Tok.is(tok::l_brace)) { NullablePtr Body = parseStmtBrace(diag::invalid_diagnostic); if (Body.isNull()) FE = 0; // FIXME: Should do some sort of error recovery here. else FE->setBody(Body.get()); } else { // Note, we just discard FE here. It is bump pointer allocated, so this // is fine (if suboptimal). FE = 0; } } // Create the decl for the func and add it to the parent scope. FuncDecl *FD = new (Context) FuncDecl(StaticLoc, FuncLoc, Name, FuncTy, FE, CurDeclContext, ScopeInfo.isModuleScope()); if (Attributes.isValid()) FD->getMutableAttrs() = Attributes; ScopeInfo.addToScope(FD); return FD; } /// parseDeclOneOf - Parse a 'oneof' declaration, returning true (and doing no /// token skipping) on error. /// /// decl-oneof: /// 'oneof' attribute-list identifier oneof-body /// oneof-body: /// '{' oneof-element (',' oneof-element)* decl* '}' /// oneof-element: /// identifier /// identifier ':' type-annotation /// bool Parser::parseDeclOneOf(SmallVectorImpl &Decls) { SourceLoc OneOfLoc = consumeToken(tok::kw_oneof); DeclAttributes Attributes; parseAttributeList(Attributes); SourceLoc NameLoc = Tok.getLoc(); Identifier OneOfName; if (parseIdentifier(OneOfName, diag::expected_identifier_in_decl, "oneof")) return true; TypeAliasDecl *TAD = new (Context) TypeAliasDecl(NameLoc, OneOfName, Type(), CurDeclContext, ScopeInfo.isModuleScope()); Decls.push_back(TAD); SourceLoc LBLoc, RBLoc; if (parseToken(tok::l_brace, LBLoc, diag::expected_lbrace_oneof_type)) return true; SmallVector ElementInfos; // Parse the comma separated list of oneof elements. while (Tok.is(tok::identifier)) { OneOfElementInfo ElementInfo; ElementInfo.Name = Tok.getText(); ElementInfo.NameLoc = Tok.getLoc(); ElementInfo.EltType = 0; consumeToken(tok::identifier); // See if we have a type specifier for this oneof element. If so, parse it. if (consumeIf(tok::colon) && parseTypeAnnotation(ElementInfo.EltType, diag::expected_type_oneof_element)) { skipUntil(tok::r_brace); return true; } ElementInfos.push_back(ElementInfo); // Require comma separation. if (!consumeIf(tok::comma)) break; } OneOfType *Result = actOnOneOfType(OneOfLoc, Attributes, ElementInfos, TAD); // Parse the body as a series of decls. SmallVector MemberDecls; while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { if (parseDecl(MemberDecls, PD_HasContainerType|PD_DisallowVar|PD_DisallowOperators)) skipUntilDeclRBrace(); } parseMatchingToken(tok::r_brace, RBLoc, diag::expected_rbrace_oneof_type, LBLoc, diag::opening_brace); // If there were members, create an 'extension' to hold them. if (!MemberDecls.empty()) Decls.push_back(actOnDeclExtension(SourceLoc(), Result, MemberDecls)); return false; } /// actOnOneOfType - Generate a oneof type and wire it into the scope tree. /// This is functionality shared by the different sugared forms of oneof types. /// OneOfType *Parser::actOnOneOfType(SourceLoc OneOfLoc, const DeclAttributes &Attrs, ArrayRef Elts, TypeAliasDecl *PrettyTypeName) { // No attributes are valid on oneof types at this time. if (!Attrs.empty()) diagnose(Attrs.LSquareLoc, diag::oneof_attributes); llvm::SmallPtrSet SeenSoFar; SmallVector EltDecls; // If we have a PrettyTypeName to use, use it. Otherwise, just assign the // constructors a temporary dummy type. Type AliasTy = PrettyTypeName->getAliasType(); for (const OneOfElementInfo &Elt : Elts) { Identifier NameI = Context.getIdentifier(Elt.Name); // If this was multiply defined, reject it. if (!SeenSoFar.insert(NameI.get())) { diagnose(Elt.NameLoc, diag::duplicate_oneof_element, Elt.Name); // FIXME: Do we care enough to make this efficient? for (unsigned I = 0, N = EltDecls.size(); I != N; ++I) { if (EltDecls[I]->getName() == NameI) { diagnose(EltDecls[I]->getLocStart(), diag::previous_definition, NameI); break; } } // Don't copy this element into NewElements. continue; } Type EltTy = AliasTy; if (Type ArgTy = Elt.EltType) EltTy = FunctionType::get(ArgTy, EltTy, Context); // Create a decl for each element, giving each a temporary type. EltDecls.push_back(new (Context) OneOfElementDecl(Elt.NameLoc, NameI, EltTy, Elt.EltType, CurDeclContext, ScopeInfo.isModuleScope())); } OneOfType *Result = OneOfType::getNew(OneOfLoc, EltDecls, PrettyTypeName); for (OneOfElementDecl *D : EltDecls) D->setDeclContext(Result); // Complete the type alias to its actual type. PrettyTypeName->setUnderlyingType(Result); // Inject the type name into the containing scope so that it can be found as a // metatype. ScopeInfo.addToScope(PrettyTypeName); return Result; } /// parseDeclStruct - Parse a 'struct' declaration, returning null (and doing no /// token skipping) on error. A 'struct' is just syntactic sugar for a oneof /// with a single element. /// /// decl-struct: /// 'struct' attribute-list identifier '{' decl-struct-body '} /// decl-struct-body: /// type-tuple-body? decl* /// bool Parser::parseDeclStruct(SmallVectorImpl &Decls) { SourceLoc StructLoc = consumeToken(tok::kw_struct); DeclAttributes Attributes; parseAttributeList(Attributes); Identifier StructName; SourceLoc LBLoc, RBLoc; if (parseIdentifier(StructName, diag::expected_identifier_in_decl, "struct")|| parseToken(tok::l_brace, LBLoc, diag::expected_lbrace_struct)) return true; // Get the TypeAlias for the name that we'll eventually have. TypeAliasDecl *TAD = new (Context) TypeAliasDecl(StructLoc, StructName, Type(), CurDeclContext, ScopeInfo.isModuleScope()); // Parse elements of the body as a tuple body. Type BodyTy; if (parseTypeTupleBody(LBLoc, BodyTy)) return true; assert(isa(BodyTy.getPointer())); // Reject any unnamed members. for (auto Elt : BodyTy->castTo()->getFields()) if (!Elt.hasName()) { // FIXME: Mark erroneous, terrible location info. Probably should just // have custom parsing logic instead of reusing type-tuple-body. diagnose(LBLoc, diag::struct_unnamed_member); } // Parse the body as a series of decls. SmallVector MemberDecls; while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { if (parseDecl(MemberDecls, PD_HasContainerType|PD_DisallowVar|PD_DisallowOperators)) skipUntilDeclRBrace(); } if (parseMatchingToken(tok::r_brace, RBLoc, diag::expected_rbrace_struct, LBLoc, diag::opening_brace)) return true; Decls.push_back(TAD); // The 'struct' is syntactically fine, invoke the semantic actions for the // syntactically expanded oneof type. Struct declarations are just sugar for // other existing constructs. Parser::OneOfElementInfo ElementInfo; ElementInfo.Name = StructName.str(); ElementInfo.NameLoc = StructLoc; ElementInfo.EltType = BodyTy; OneOfType *OneOfTy = actOnOneOfType(StructLoc, Attributes, ElementInfo, TAD); assert(OneOfTy->isTransparentType() && "Somehow isn't a struct?"); // If there were members, create an 'extension' to hold them. if (!MemberDecls.empty()) Decls.push_back(actOnDeclExtension(StructLoc, OneOfTy, MemberDecls)); return false; } /// parseDeclProtocol - Parse a 'protocol' declaration, returning null (and /// doing no token skipping) on error. /// /// decl-protocol: /// 'protocol' attribute-list identifier protocol-body /// Decl *Parser::parseDeclProtocol() { SourceLoc ProtocolLoc = consumeToken(tok::kw_protocol); DeclAttributes Attributes; parseAttributeList(Attributes); SourceLoc NameLoc = Tok.getLoc(); Identifier ProtocolName; if (parseIdentifier(ProtocolName, diag::expected_identifier_in_decl, "protocol")) return 0; TypeAliasDecl *TAD = new (Context) TypeAliasDecl(NameLoc, ProtocolName, Type(), CurDeclContext, ScopeInfo.isModuleScope()); if (parseProtocolBody(ProtocolLoc, Attributes, TAD)) return 0; return TAD; } /// protocol-body: /// '{' protocol-member* '}' /// protocol-member: /// decl-func /// decl-var-simple /// // 'typealias' identifier /// bool Parser::parseProtocolBody(SourceLoc ProtocolLoc, const DeclAttributes &Attributes, TypeAliasDecl *TypeName) { // Parse the body. if (parseToken(tok::l_brace, diag::expected_lbrace_protocol_type)) return true; // Parse the list of protocol elements. SmallVector Elements; do { switch (Tok.getKind()) { default: diagnose(Tok, diag::expected_protocol_member); return true; case tok::r_brace: // End of protocol body. break; // FIXME: use standard parseDecl loop. case tok::kw_static: case tok::kw_func: Elements.push_back(parseDeclFunc(Tok.is(tok::kw_func))); if (Elements.back() == 0) return true; break; case tok::kw_var: Elements.push_back(parseDeclVarSimple()); if (Elements.back() == 0) return true; break; } } while (Tok.isNot(tok::r_brace)); consumeToken(tok::r_brace); // Act on what we've parsed. if (!Attributes.empty()) diagnose(Attributes.LSquareLoc, diag::protocol_attributes); ProtocolType *NewProto = ProtocolType::getNew(ProtocolLoc, Elements,TypeName); // Install all of the members of protocol into the protocol's DeclContext. for (Decl *D : Elements) D->setDeclContext(NewProto); // Complete the pretty name for this type. TypeName->setUnderlyingType(NewProto); return false; }