//===--- 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); 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); // Turn our little catalog of unresolved types and identifier types into a // list on the TranslationUnit, so NameBinding can bind them. SmallVector UnresolvedTypeList; for (TypeAliasDecl *Decl : UnresolvedTypeNames) { if (!Decl->hasUnderlyingType()) UnresolvedTypeList.push_back(Decl); } TU->setUnresolvedTypes(Context.AllocateCopy(UnresolvedTypeList)); TU->setUnresolvedIdentifierTypes( Context.AllocateCopy(llvm::makeArrayRef(UnresolvedIdentifierTypes))); UnresolvedTypeNames.clear(); 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(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_plus: 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) || isa(D)) && !(Flags & PD_AllowTopLevel)) diagnose(D->getLocStart(), diag::decl_inner_scope); if (isa(D) && (Flags & PD_DisallowVar)) { 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.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(); 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!"); } /// parseDeclVar - Parse a 'var' declaration, returning null (and doing no /// token skipping) on error. /// /// decl-var: /// 'var' attribute-list var-name value-specifier bool Parser::parseDeclVar(SmallVectorImpl &Decls) { SourceLoc VarLoc = consumeToken(tok::kw_var); DeclAttributes Attributes; parseAttributeList(Attributes); NullablePtr pattern = parsePattern(); if (pattern.isNull()) return true; Type Ty; NullablePtr Init; if (consumeIf(tok::equal)) { Init = parseExpr(diag::expected_initializer_expr); if (Init.isNull()) return true; } 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' attribute-list 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); } /// 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: /// 'plus'? '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 'plus' 'func'. /// FuncDecl *Parser::parseDeclFunc(bool hasContainerType) { SourceLoc PlusLoc; if (Tok.is(tok::kw_plus)) { PlusLoc = consumeToken(tok::kw_plus); // Reject 'plus' functions at global scope. if (!hasContainerType) { diagnose(Tok, diag::plus_func_decl_global_scope); PlusLoc = 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 plus 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 && !PlusLoc.isValid()) { VarDecl *D = new (Context) VarDecl(SourceLoc(), Context.getIdentifier("this"), Type(), CurDeclContext); Pattern *P = new (Context) NamedPattern(D); P = new (Context) TypedPattern(P, UnstructuredDependentType::get(Context)); Params.push_back(P); } 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(PlusLoc, FuncLoc, Name, FuncTy, FE, CurDeclContext); 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); 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)); } 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); // 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(SourceLoc(), 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); 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_plus: 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; }