static void printModuleId(llvm::raw_ostream &OS, const ModuleId &Id) { for (unsigned I = 0, N = Id.size(); I != N; ++I) { if (I) OS << "."; OS << Id[I].first; } }
/// \brief Parse a module-id. /// /// module-id: /// identifier /// identifier '.' module-id /// /// \returns true if an error occurred, false otherwise. bool ModuleMapParser::parseModuleId(ModuleId &Id) { Id.clear(); do { if (Tok.is(MMToken::Identifier)) { Id.push_back(std::make_pair(Tok.getString(), Tok.getLocation())); consumeToken(); } else { Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module_name); return true; } if (!Tok.is(MMToken::Period)) break; consumeToken(); } while (true); return false; }
/// \brief Parse a module export declaration. /// /// export-declaration: /// 'export' wildcard-module-id /// /// wildcard-module-id: /// identifier /// '*' /// identifier '.' wildcard-module-id void ModuleMapParser::parseExportDecl() { assert(Tok.is(MMToken::ExportKeyword)); SourceLocation ExportLoc = consumeToken(); // Parse the module-id with an optional wildcard at the end. ModuleId ParsedModuleId; bool Wildcard = false; do { if (Tok.is(MMToken::Identifier)) { ParsedModuleId.push_back(std::make_pair(Tok.getString(), Tok.getLocation())); consumeToken(); if (Tok.is(MMToken::Period)) { consumeToken(); continue; } break; } if(Tok.is(MMToken::Star)) { Wildcard = true; consumeToken(); break; } Diags.Report(Tok.getLocation(), diag::err_mmap_export_module_id); HadError = true; return; } while (true); Module::UnresolvedExportDecl Unresolved = { ExportLoc, ParsedModuleId, Wildcard }; ActiveModule->UnresolvedExports.push_back(Unresolved); }
/// \brief Parse a module declaration. /// /// module-declaration: /// 'explicit'[opt] 'framework'[opt] 'module' module-id attributes[opt] /// { module-member* } /// /// attributes: /// attribute attributes /// attribute /// /// attribute: /// [ identifier ] /// /// module-member: /// requires-declaration /// header-declaration /// submodule-declaration /// export-declaration /// /// submodule-declaration: /// module-declaration /// inferred-submodule-declaration void ModuleMapParser::parseModuleDecl() { assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) || Tok.is(MMToken::FrameworkKeyword)); // Parse 'explicit' or 'framework' keyword, if present. SourceLocation ExplicitLoc; bool Explicit = false; bool Framework = false; // Parse 'explicit' keyword, if present. if (Tok.is(MMToken::ExplicitKeyword)) { ExplicitLoc = consumeToken(); Explicit = true; } // Parse 'framework' keyword, if present. if (Tok.is(MMToken::FrameworkKeyword)) { consumeToken(); Framework = true; } // Parse 'module' keyword. if (!Tok.is(MMToken::ModuleKeyword)) { Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module); consumeToken(); HadError = true; return; } consumeToken(); // 'module' keyword // If we have a wildcard for the module name, this is an inferred submodule. // Parse it. if (Tok.is(MMToken::Star)) return parseInferredSubmoduleDecl(Explicit); // Parse the module name. ModuleId Id; if (parseModuleId(Id)) { HadError = true; return; } if (ActiveModule) { if (Id.size() > 1) { Diags.Report(Id.front().second, diag::err_mmap_nested_submodule_id) << SourceRange(Id.front().second, Id.back().second); HadError = true; return; } } else if (Id.size() == 1 && Explicit) { // Top-level modules can't be explicit. Diags.Report(ExplicitLoc, diag::err_mmap_explicit_top_level); Explicit = false; ExplicitLoc = SourceLocation(); HadError = true; } Module *PreviousActiveModule = ActiveModule; if (Id.size() > 1) { // This module map defines a submodule. Go find the module of which it // is a submodule. ActiveModule = 0; for (unsigned I = 0, N = Id.size() - 1; I != N; ++I) { if (Module *Next = Map.lookupModuleQualified(Id[I].first, ActiveModule)) { ActiveModule = Next; continue; } if (ActiveModule) { Diags.Report(Id[I].second, diag::err_mmap_missing_module_qualified) << Id[I].first << ActiveModule->getTopLevelModule(); } else { Diags.Report(Id[I].second, diag::err_mmap_expected_module_name); } HadError = true; return; } } StringRef ModuleName = Id.back().first; SourceLocation ModuleNameLoc = Id.back().second; // Parse the optional attribute list. bool IsSystem = false; while (Tok.is(MMToken::LSquare)) { // Consume the '['. SourceLocation LSquareLoc = consumeToken(); // Check whether we have an attribute name here. if (!Tok.is(MMToken::Identifier)) { Diags.Report(Tok.getLocation(), diag::err_mmap_expected_attribute); skipUntil(MMToken::RSquare); if (Tok.is(MMToken::RSquare)) consumeToken(); continue; } // Decode the attribute name. AttributeKind Attribute = llvm::StringSwitch<AttributeKind>(Tok.getString()) .Case("system", AT_system) .Default(AT_unknown); switch (Attribute) { case AT_unknown: Diags.Report(Tok.getLocation(), diag::warn_mmap_unknown_attribute) << Tok.getString(); break; case AT_system: IsSystem = true; break; } consumeToken(); // Consume the ']'. if (!Tok.is(MMToken::RSquare)) { Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rsquare); Diags.Report(LSquareLoc, diag::note_mmap_lsquare_match); skipUntil(MMToken::RSquare); } if (Tok.is(MMToken::RSquare)) consumeToken(); } // Parse the opening brace. if (!Tok.is(MMToken::LBrace)) { Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace) << ModuleName; HadError = true; return; } SourceLocation LBraceLoc = consumeToken(); // Determine whether this (sub)module has already been defined. if (Module *Existing = Map.lookupModuleQualified(ModuleName, ActiveModule)) { if (Existing->DefinitionLoc.isInvalid() && !ActiveModule) { // Skip the module definition. skipUntil(MMToken::RBrace); if (Tok.is(MMToken::RBrace)) consumeToken(); else { Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace); Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match); HadError = true; } return; } Diags.Report(ModuleNameLoc, diag::err_mmap_module_redefinition) << ModuleName; Diags.Report(Existing->DefinitionLoc, diag::note_mmap_prev_definition); // Skip the module definition. skipUntil(MMToken::RBrace); if (Tok.is(MMToken::RBrace)) consumeToken(); HadError = true; return; } // Start defining this module. ActiveModule = Map.findOrCreateModule(ModuleName, ActiveModule, Framework, Explicit).first; ActiveModule->DefinitionLoc = ModuleNameLoc; if (IsSystem) ActiveModule->IsSystem = true; bool Done = false; do { switch (Tok.Kind) { case MMToken::EndOfFile: case MMToken::RBrace: Done = true; break; case MMToken::ExplicitKeyword: case MMToken::FrameworkKeyword: case MMToken::ModuleKeyword: parseModuleDecl(); break; case MMToken::ExportKeyword: parseExportDecl(); break; case MMToken::RequiresKeyword: parseRequiresDecl(); break; case MMToken::UmbrellaKeyword: { SourceLocation UmbrellaLoc = consumeToken(); if (Tok.is(MMToken::HeaderKeyword)) parseHeaderDecl(UmbrellaLoc); else parseUmbrellaDirDecl(UmbrellaLoc); break; } case MMToken::HeaderKeyword: parseHeaderDecl(SourceLocation()); break; default: Diags.Report(Tok.getLocation(), diag::err_mmap_expected_member); consumeToken(); break; } } while (!Done); if (Tok.is(MMToken::RBrace)) consumeToken(); else { Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace); Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match); HadError = true; } // We're done parsing this module. Pop back to the previous module. ActiveModule = PreviousActiveModule; }