compiler.c++ (53029B)
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 2 // Licensed under the MIT License: 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 #include "compiler.h" 23 #include "parser.h" // only for generateChildId() 24 #include <kj/mutex.h> 25 #include <kj/arena.h> 26 #include <kj/vector.h> 27 #include <kj/debug.h> 28 #include <capnp/message.h> 29 #include <map> 30 #include <set> 31 #include <unordered_map> 32 #include "node-translator.h" 33 34 namespace capnp { 35 namespace compiler { 36 37 typedef std::unordered_map<uint64_t, Orphan<schema::Node::SourceInfo::Reader>> SourceInfoMap; 38 39 class Compiler::Alias { 40 public: 41 Alias(CompiledModule& module, Node& parent, const Expression::Reader& targetName) 42 : module(module), parent(parent), targetName(targetName) {} 43 44 kj::Maybe<Resolver::ResolveResult> compile(); 45 46 private: 47 CompiledModule& module; 48 Node& parent; 49 Expression::Reader targetName; 50 kj::Maybe<Resolver::ResolveResult> target; 51 Orphan<schema::Brand> brandOrphan; 52 bool initialized = false; 53 }; 54 55 class Compiler::Node final: public Resolver { 56 // Passes through four states: 57 // - Stub: On initial construction, the Node is just a placeholder object. Its ID has been 58 // determined, and it is placed in its parent's member table as well as the compiler's 59 // nodes-by-ID table. 60 // - Expanded: Nodes have been constructed for all of this Node's nested children. This happens 61 // the first time a lookup is performed for one of those children. 62 // - Bootstrap: A NodeTranslator has been built and advanced to the bootstrap phase. 63 // - Finished: A final Schema object has been constructed. 64 65 public: 66 explicit Node(CompiledModule& module); 67 // Create a root node representing the given file. May 68 69 Node(Node& parent, const Declaration::Reader& declaration); 70 // Create a child node. 71 72 Node(kj::StringPtr name, Declaration::Which kind, 73 List<Declaration::BrandParameter>::Reader genericParams); 74 // Create a dummy node representing a built-in declaration, like "Int32" or "true". 75 76 uint64_t getId() { return id; } 77 uint getParameterCount() { return genericParamCount; } 78 Declaration::Which getKind() { return kind; } 79 80 kj::Maybe<Schema> getBootstrapSchema(); 81 kj::Maybe<schema::Node::Reader> getFinalSchema(); 82 void loadFinalSchema(const SchemaLoader& loader); 83 84 void traverse(uint eagerness, std::unordered_map<Node*, uint>& seen, 85 const SchemaLoader& finalLoader, 86 kj::Vector<schema::Node::SourceInfo::Reader>& sourceInfo); 87 // Get the final schema for this node, and also possibly traverse the node's children and 88 // dependencies to ensure that they are loaded, depending on the mode. 89 90 void addError(kj::StringPtr error); 91 // Report an error on this Node. 92 93 // implements Resolver --------------------------------------------- 94 kj::Maybe<ResolveResult> resolve(kj::StringPtr name) override; 95 kj::Maybe<ResolveResult> resolveMember(kj::StringPtr name) override; 96 ResolvedDecl resolveBuiltin(Declaration::Which which) override; 97 ResolvedDecl resolveId(uint64_t id) override; 98 kj::Maybe<ResolvedDecl> getParent() override; 99 ResolvedDecl getTopScope() override; 100 kj::Maybe<Schema> resolveBootstrapSchema( 101 uint64_t id, schema::Brand::Reader brand) override; 102 kj::Maybe<schema::Node::Reader> resolveFinalSchema(uint64_t id) override; 103 kj::Maybe<ResolvedDecl> resolveImport(kj::StringPtr name) override; 104 kj::Maybe<kj::Array<const byte>> readEmbed(kj::StringPtr name) override; 105 kj::Maybe<Type> resolveBootstrapType(schema::Type::Reader type, Schema scope) override; 106 107 private: 108 CompiledModule* module; // null iff isBuiltin is true 109 kj::Maybe<Node&> parent; 110 111 Declaration::Reader declaration; 112 // AST of the declaration parsed from the schema file. May become invalid once the content 113 // state has reached FINISHED. 114 115 uint64_t id; 116 // The ID of this node, either taken from the AST or computed based on the parent. Or, a dummy 117 // value, if duplicates were detected. 118 119 kj::StringPtr displayName; 120 // Fully-qualified display name for this node. For files, this is just the file name, otherwise 121 // it is "filename:Path.To.Decl". 122 123 Declaration::Which kind; 124 // Kind of node. 125 126 uint genericParamCount; 127 // Number of generic parameters. 128 129 bool isBuiltin; 130 // Whether this is a bulit-in declaration, like "Int32" or "true". 131 132 uint32_t startByte; 133 uint32_t endByte; 134 // Start and end byte for reporting general errors. 135 136 struct Content { 137 inline Content(): state(STUB) {} 138 139 enum State { 140 STUB, 141 EXPANDED, 142 BOOTSTRAP, 143 FINISHED 144 }; 145 State state; 146 // Indicates which fields below are valid. 147 148 inline bool stateHasReached(State minimumState) { 149 return state >= minimumState; 150 } 151 inline void advanceState(State newState) { 152 state = newState; 153 } 154 155 // EXPANDED ------------------------------------ 156 157 typedef std::multimap<kj::StringPtr, kj::Own<Node>> NestedNodesMap; 158 NestedNodesMap nestedNodes; 159 kj::Vector<Node*> orderedNestedNodes; 160 // multimap in case of duplicate member names -- we still want to compile them, even if it's an 161 // error. 162 163 typedef std::multimap<kj::StringPtr, kj::Own<Alias>> AliasMap; 164 AliasMap aliases; 165 // The "using" declarations. These are just links to nodes elsewhere. 166 167 // BOOTSTRAP ----------------------------------- 168 169 NodeTranslator* translator; 170 // Node translator, allocated in the bootstrap arena. 171 172 kj::Maybe<Schema> bootstrapSchema; 173 // The schema built in the bootstrap loader. Null if the bootstrap loader threw an exception. 174 175 // FINISHED ------------------------------------ 176 177 kj::Maybe<schema::Node::Reader> finalSchema; 178 // The completed schema, ready to load into the real schema loader. 179 180 kj::Array<schema::Node::Reader> auxSchemas; 181 // Schemas for all auxiliary nodes built by the NodeTranslator. 182 183 kj::Array<schema::Node::SourceInfo::Reader> sourceInfo; 184 // All source info structs as built by the NodeTranslator. 185 }; 186 187 Content guardedContent; // Read using getContent() only! 188 bool inGetContent = false; // True while getContent() is running; detects cycles. 189 190 kj::Maybe<schema::Node::Reader> loadedFinalSchema; 191 // Copy of `finalSchema` as loaded into the final schema loader. This doesn't go away if the 192 // workspace is destroyed. 193 194 // --------------------------------------------- 195 196 static uint64_t generateId(uint64_t parentId, kj::StringPtr declName, 197 Declaration::Id::Reader declId); 198 // Extract the ID from the declaration, or if it has none, generate one based on the name and 199 // parent ID. 200 201 static kj::StringPtr joinDisplayName(kj::Arena& arena, Node& parent, kj::StringPtr declName); 202 // Join the parent's display name with the child's unqualified name to construct the child's 203 // display name. 204 205 kj::Maybe<Content&> getContent(Content::State minimumState); 206 // Advances the content to at least the given state and returns it. Returns null if getContent() 207 // is being called recursively and the given state has not yet been reached, as this indicates 208 // that the declaration recursively depends on itself. 209 210 void traverseNodeDependencies(const schema::Node::Reader& schemaNode, uint eagerness, 211 std::unordered_map<Node*, uint>& seen, 212 const SchemaLoader& finalLoader, 213 kj::Vector<schema::Node::SourceInfo::Reader>& sourceInfo); 214 void traverseType(const schema::Type::Reader& type, uint eagerness, 215 std::unordered_map<Node*, uint>& seen, 216 const SchemaLoader& finalLoader, 217 kj::Vector<schema::Node::SourceInfo::Reader>& sourceInfo); 218 void traverseBrand(const schema::Brand::Reader& brand, uint eagerness, 219 std::unordered_map<Node*, uint>& seen, 220 const SchemaLoader& finalLoader, 221 kj::Vector<schema::Node::SourceInfo::Reader>& sourceInfo); 222 void traverseAnnotations(const List<schema::Annotation>::Reader& annotations, uint eagerness, 223 std::unordered_map<Node*, uint>& seen, 224 const SchemaLoader& finalLoader, 225 kj::Vector<schema::Node::SourceInfo::Reader>& sourceInfo); 226 void traverseDependency(uint64_t depId, uint eagerness, 227 std::unordered_map<Node*, uint>& seen, 228 const SchemaLoader& finalLoader, 229 kj::Vector<schema::Node::SourceInfo::Reader>& sourceInfo, 230 bool ignoreIfNotFound = false); 231 // Helpers for traverse(). 232 }; 233 234 class Compiler::CompiledModule { 235 public: 236 CompiledModule(Compiler::Impl& compiler, Module& parserModule); 237 238 Compiler::Impl& getCompiler() { return compiler; } 239 240 ErrorReporter& getErrorReporter() { return parserModule; } 241 ParsedFile::Reader getParsedFile() { return content.getReader(); } 242 Node& getRootNode() { return rootNode; } 243 kj::StringPtr getSourceName() { return parserModule.getSourceName(); } 244 245 kj::Maybe<CompiledModule&> importRelative(kj::StringPtr importPath); 246 kj::Maybe<kj::Array<const byte>> embedRelative(kj::StringPtr importPath); 247 248 Orphan<List<schema::CodeGeneratorRequest::RequestedFile::Import>> 249 getFileImportTable(Orphanage orphanage); 250 251 private: 252 Compiler::Impl& compiler; 253 Module& parserModule; 254 MallocMessageBuilder contentArena; 255 Orphan<ParsedFile> content; 256 Node rootNode; 257 }; 258 259 class Compiler::Impl: public SchemaLoader::LazyLoadCallback { 260 public: 261 explicit Impl(AnnotationFlag annotationFlag); 262 virtual ~Impl() noexcept(false); 263 264 uint64_t add(Module& module); 265 kj::Maybe<uint64_t> lookup(uint64_t parent, kj::StringPtr childName); 266 kj::Maybe<schema::Node::SourceInfo::Reader> getSourceInfo(uint64_t id); 267 Orphan<List<schema::CodeGeneratorRequest::RequestedFile::Import>> 268 getFileImportTable(Module& module, Orphanage orphanage); 269 Orphan<List<schema::Node::SourceInfo>> getAllSourceInfo(Orphanage orphanage); 270 void eagerlyCompile(uint64_t id, uint eagerness, const SchemaLoader& loader); 271 CompiledModule& addInternal(Module& parsedModule); 272 273 struct Workspace { 274 // Scratch space where stuff can be allocated while working. The Workspace is available 275 // whenever nodes are actively being compiled, then is destroyed once control exits the 276 // compiler. Note that since nodes are compiled lazily, a new Workspace may have to be 277 // constructed in order to compile more nodes later. 278 279 MallocMessageBuilder message; 280 Orphanage orphanage; 281 // Orphanage for allocating temporary Cap'n Proto objects. 282 283 kj::Arena arena; 284 // Arena for allocating temporary native objects. Note that objects in `arena` may contain 285 // pointers into `message` that will be manipulated on destruction, so `arena` must be declared 286 // after `message`. 287 288 SchemaLoader bootstrapLoader; 289 // Loader used to load bootstrap schemas. The bootstrap schema nodes are similar to the final 290 // versions except that any value expressions which depend on knowledge of other types (e.g. 291 // default values for struct fields) are left unevaluated (the values in the schema are empty). 292 // These bootstrap schemas can then be plugged into the dynamic API and used to evaluate these 293 // remaining values. 294 295 inline explicit Workspace(const SchemaLoader::LazyLoadCallback& loaderCallback) 296 : orphanage(message.getOrphanage()), 297 bootstrapLoader(loaderCallback) {} 298 }; 299 300 kj::Arena& getNodeArena() { return nodeArena; } 301 // Arena where nodes and other permanent objects should be allocated. 302 303 Workspace& getWorkspace() { return workspace; } 304 // Temporary workspace that can be used to construct bootstrap objects. 305 306 inline bool shouldCompileAnnotations() { 307 return annotationFlag == AnnotationFlag::COMPILE_ANNOTATIONS; 308 } 309 310 void clearWorkspace(); 311 // Reset the temporary workspace. 312 313 uint64_t addNode(uint64_t desiredId, Node& node); 314 // Add the given node to the by-ID map under the given ID. If another node with the same ID 315 // already exists, choose a new one arbitrarily and use that instead. Return the ID that was 316 // finally used. 317 318 kj::Maybe<Node&> findNode(uint64_t id); 319 320 kj::Maybe<Node&> lookupBuiltin(kj::StringPtr name); 321 Node& getBuiltin(Declaration::Which which); 322 323 void load(const SchemaLoader& loader, uint64_t id) const override; 324 // SchemaLoader callback for the bootstrap loader. 325 326 void loadFinal(const SchemaLoader& loader, uint64_t id); 327 // Called from the SchemaLoader callback for the final loader. 328 329 private: 330 AnnotationFlag annotationFlag; 331 332 kj::Arena nodeArena; 333 // Arena used to allocate nodes and other permanent objects. 334 335 std::unordered_map<Module*, kj::Own<CompiledModule>> modules; 336 // Map of parser modules to compiler modules. 337 338 Workspace workspace; 339 // The temporary workspace. This field must be declared after `modules` because objects 340 // allocated in the workspace may hold references to the compiled modules in `modules`. 341 342 std::unordered_map<uint64_t, Node*> nodesById; 343 // Map of nodes by ID. 344 345 std::unordered_map<uint64_t, schema::Node::SourceInfo::Reader> sourceInfoById; 346 // Map of SourceInfos by ID, including SourceInfos for groups and param sturcts (which are not 347 // listed in nodesById). 348 349 std::map<kj::StringPtr, kj::Own<Node>> builtinDecls; 350 std::map<Declaration::Which, Node*> builtinDeclsByKind; 351 // Map of built-in declarations, like "Int32" and "List", which make up the global scope. 352 353 uint64_t nextBogusId = 1000; 354 // Counter for assigning bogus IDs to nodes whose real ID is a duplicate. 355 }; 356 357 // ======================================================================================= 358 359 kj::Maybe<Resolver::ResolveResult> Compiler::Alias::compile() { 360 if (!initialized) { 361 initialized = true; 362 363 auto& workspace = module.getCompiler().getWorkspace(); 364 brandOrphan = workspace.orphanage.newOrphan<schema::Brand>(); 365 366 // If the Workspace is destroyed, revert the alias to the uninitialized state, because the 367 // orphan we created is no longer valid in this case. 368 workspace.arena.copy(kj::defer([this]() { 369 initialized = false; 370 brandOrphan = Orphan<schema::Brand>(); 371 })); 372 373 target = NodeTranslator::compileDecl( 374 parent.getId(), parent.getParameterCount(), parent, 375 module.getErrorReporter(), targetName, brandOrphan.get()); 376 } 377 378 return target; 379 } 380 381 // ======================================================================================= 382 383 Compiler::Node::Node(CompiledModule& module) 384 : module(&module), 385 parent(nullptr), 386 declaration(module.getParsedFile().getRoot()), 387 id(generateId(0, declaration.getName().getValue(), declaration.getId())), 388 displayName(module.getSourceName()), 389 kind(declaration.which()), 390 genericParamCount(declaration.getParameters().size()), 391 isBuiltin(false) { 392 auto name = declaration.getName(); 393 if (name.getValue().size() > 0) { 394 startByte = name.getStartByte(); 395 endByte = name.getEndByte(); 396 } else { 397 startByte = declaration.getStartByte(); 398 endByte = declaration.getEndByte(); 399 } 400 401 id = module.getCompiler().addNode(id, *this); 402 } 403 404 Compiler::Node::Node(Node& parent, const Declaration::Reader& declaration) 405 : module(parent.module), 406 parent(parent), 407 declaration(declaration), 408 id(generateId(parent.id, declaration.getName().getValue(), declaration.getId())), 409 displayName(joinDisplayName(parent.module->getCompiler().getNodeArena(), 410 parent, declaration.getName().getValue())), 411 kind(declaration.which()), 412 genericParamCount(declaration.getParameters().size()), 413 isBuiltin(false) { 414 auto name = declaration.getName(); 415 if (name.getValue().size() > 0) { 416 startByte = name.getStartByte(); 417 endByte = name.getEndByte(); 418 } else { 419 startByte = declaration.getStartByte(); 420 endByte = declaration.getEndByte(); 421 } 422 423 id = module->getCompiler().addNode(id, *this); 424 } 425 426 Compiler::Node::Node(kj::StringPtr name, Declaration::Which kind, 427 List<Declaration::BrandParameter>::Reader genericParams) 428 : module(nullptr), 429 parent(nullptr), 430 // It's helpful if these have unique IDs. Real type IDs can't be under 2^31 anyway. 431 id(1000 + static_cast<uint>(kind)), 432 displayName(name), 433 kind(kind), 434 genericParamCount(genericParams.size()), 435 isBuiltin(true), 436 startByte(0), 437 endByte(0) {} 438 439 uint64_t Compiler::Node::generateId(uint64_t parentId, kj::StringPtr declName, 440 Declaration::Id::Reader declId) { 441 if (declId.isUid()) { 442 return declId.getUid().getValue(); 443 } 444 445 return generateChildId(parentId, declName); 446 } 447 448 kj::StringPtr Compiler::Node::joinDisplayName( 449 kj::Arena& arena, Node& parent, kj::StringPtr declName) { 450 kj::ArrayPtr<char> result = arena.allocateArray<char>( 451 parent.displayName.size() + declName.size() + 2); 452 453 size_t separatorPos = parent.displayName.size(); 454 memcpy(result.begin(), parent.displayName.begin(), separatorPos); 455 result[separatorPos] = parent.parent == nullptr ? ':' : '.'; 456 memcpy(result.begin() + separatorPos + 1, declName.begin(), declName.size()); 457 result[result.size() - 1] = '\0'; 458 return kj::StringPtr(result.begin(), result.size() - 1); 459 } 460 461 kj::Maybe<Compiler::Node::Content&> Compiler::Node::getContent(Content::State minimumState) { 462 KJ_REQUIRE(!isBuiltin, "illegal method call for built-in declaration"); 463 464 auto& content = guardedContent; 465 466 if (content.stateHasReached(minimumState)) { 467 return content; 468 } 469 470 if (inGetContent) { 471 addError("Declaration recursively depends on itself."); 472 return nullptr; 473 } 474 475 inGetContent = true; 476 KJ_DEFER(inGetContent = false); 477 478 switch (content.state) { 479 case Content::STUB: { 480 if (minimumState <= Content::STUB) break; 481 482 // Expand the child nodes. 483 auto& arena = module->getCompiler().getNodeArena(); 484 485 for (auto nestedDecl: declaration.getNestedDecls()) { 486 switch (nestedDecl.which()) { 487 case Declaration::FILE: 488 case Declaration::CONST: 489 case Declaration::ANNOTATION: 490 case Declaration::ENUM: 491 case Declaration::STRUCT: 492 case Declaration::INTERFACE: { 493 kj::Own<Node> subNode = arena.allocateOwn<Node>(*this, nestedDecl); 494 kj::StringPtr name = nestedDecl.getName().getValue(); 495 content.orderedNestedNodes.add(subNode); 496 content.nestedNodes.insert(std::make_pair(name, kj::mv(subNode))); 497 break; 498 } 499 500 case Declaration::USING: { 501 kj::Own<Alias> alias = arena.allocateOwn<Alias>( 502 *module, *this, nestedDecl.getUsing().getTarget()); 503 kj::StringPtr name = nestedDecl.getName().getValue(); 504 content.aliases.insert(std::make_pair(name, kj::mv(alias))); 505 break; 506 } 507 case Declaration::ENUMERANT: 508 case Declaration::FIELD: 509 case Declaration::UNION: 510 case Declaration::GROUP: 511 case Declaration::METHOD: 512 case Declaration::NAKED_ID: 513 case Declaration::NAKED_ANNOTATION: 514 // Not a node. Skip. 515 break; 516 default: 517 KJ_FAIL_ASSERT("unknown declaration type", nestedDecl); 518 break; 519 } 520 } 521 522 content.advanceState(Content::EXPANDED); 523 } KJ_FALLTHROUGH; 524 525 case Content::EXPANDED: { 526 if (minimumState <= Content::EXPANDED) break; 527 528 // Construct the NodeTranslator. 529 auto& workspace = module->getCompiler().getWorkspace(); 530 531 auto schemaNode = workspace.orphanage.newOrphan<schema::Node>(); 532 auto builder = schemaNode.get(); 533 builder.setId(id); 534 builder.setDisplayName(displayName); 535 // TODO(cleanup): Would be better if we could remember the prefix length from before we 536 // added this decl's name to the end. 537 KJ_IF_MAYBE(lastDot, displayName.findLast('.')) { 538 builder.setDisplayNamePrefixLength(*lastDot + 1); 539 } 540 KJ_IF_MAYBE(lastColon, displayName.findLast(':')) { 541 if (*lastColon > builder.getDisplayNamePrefixLength()) { 542 builder.setDisplayNamePrefixLength(*lastColon + 1); 543 } 544 } 545 KJ_IF_MAYBE(p, parent) { 546 builder.setScopeId(p->id); 547 } 548 549 auto nestedNodes = builder.initNestedNodes(content.orderedNestedNodes.size()); 550 auto nestedIter = nestedNodes.begin(); 551 for (auto node: content.orderedNestedNodes) { 552 nestedIter->setName(node->declaration.getName().getValue()); 553 nestedIter->setId(node->id); 554 ++nestedIter; 555 } 556 557 content.translator = &workspace.arena.allocate<NodeTranslator>( 558 *this, module->getErrorReporter(), declaration, kj::mv(schemaNode), 559 module->getCompiler().shouldCompileAnnotations()); 560 KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&](){ 561 auto nodeSet = content.translator->getBootstrapNode(); 562 for (auto& auxNode: nodeSet.auxNodes) { 563 workspace.bootstrapLoader.loadOnce(auxNode); 564 } 565 content.bootstrapSchema = workspace.bootstrapLoader.loadOnce(nodeSet.node); 566 })) { 567 content.bootstrapSchema = nullptr; 568 // Only bother to report validation failures if we think we haven't seen any errors. 569 // Otherwise we assume that the errors caused the validation failure. 570 if (!module->getErrorReporter().hadErrors()) { 571 addError(kj::str("Internal compiler bug: Bootstrap schema failed validation:\n", 572 *exception)); 573 } 574 } 575 576 // If the Workspace is destroyed, revert the node to the EXPANDED state, because the 577 // NodeTranslator is no longer valid in this case. 578 workspace.arena.copy(kj::defer([&content]() { 579 content.bootstrapSchema = nullptr; 580 if (content.state > Content::EXPANDED) { 581 content.state = Content::EXPANDED; 582 } 583 })); 584 585 content.advanceState(Content::BOOTSTRAP); 586 } KJ_FALLTHROUGH; 587 588 case Content::BOOTSTRAP: { 589 if (minimumState <= Content::BOOTSTRAP) break; 590 591 // Create the final schema. 592 NodeTranslator::NodeSet nodeSet; 593 if (content.bootstrapSchema == nullptr) { 594 // Must have failed in an earlier stage. 595 KJ_ASSERT(module->getErrorReporter().hadErrors()); 596 nodeSet = content.translator->getBootstrapNode(); 597 } else { 598 nodeSet = content.translator->finish( 599 module->getCompiler().getWorkspace().bootstrapLoader.getUnbound(id)); 600 } 601 602 content.finalSchema = nodeSet.node; 603 content.auxSchemas = kj::mv(nodeSet.auxNodes); 604 content.sourceInfo = kj::mv(nodeSet.sourceInfo); 605 606 content.advanceState(Content::FINISHED); 607 } KJ_FALLTHROUGH; 608 609 case Content::FINISHED: 610 break; 611 } 612 613 return content; 614 } 615 616 kj::Maybe<Schema> Compiler::Node::getBootstrapSchema() { 617 KJ_IF_MAYBE(schema, loadedFinalSchema) { 618 // We don't need to rebuild the bootstrap schema if we already have a final schema. 619 return module->getCompiler().getWorkspace().bootstrapLoader.loadOnce(*schema); 620 } else KJ_IF_MAYBE(content, getContent(Content::BOOTSTRAP)) { 621 if (content->state == Content::FINISHED && content->bootstrapSchema == nullptr) { 622 // The bootstrap schema was discarded. Copy it from the final schema. 623 // (We can't just return the final schema because using it could trigger schema loader 624 // callbacks that would deadlock.) 625 KJ_IF_MAYBE(finalSchema, content->finalSchema) { 626 return module->getCompiler().getWorkspace().bootstrapLoader.loadOnce(*finalSchema); 627 } else { 628 return nullptr; 629 } 630 } else { 631 return content->bootstrapSchema; 632 } 633 } else { 634 return nullptr; 635 } 636 } 637 kj::Maybe<schema::Node::Reader> Compiler::Node::getFinalSchema() { 638 KJ_IF_MAYBE(schema, loadedFinalSchema) { 639 return *schema; 640 } else KJ_IF_MAYBE(content, getContent(Content::FINISHED)) { 641 return content->finalSchema; 642 } else { 643 return nullptr; 644 } 645 } 646 void Compiler::Node::loadFinalSchema(const SchemaLoader& loader) { 647 KJ_IF_MAYBE(content, getContent(Content::FINISHED)) { 648 KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&](){ 649 KJ_IF_MAYBE(finalSchema, content->finalSchema) { 650 KJ_MAP(auxSchema, content->auxSchemas) { 651 return loader.loadOnce(auxSchema); 652 }; 653 loadedFinalSchema = loader.loadOnce(*finalSchema).getProto(); 654 } 655 })) { 656 // Schema validation threw an exception. 657 658 // Don't try loading this again. 659 content->finalSchema = nullptr; 660 661 // Only bother to report validation failures if we think we haven't seen any errors. 662 // Otherwise we assume that the errors caused the validation failure. 663 if (!module->getErrorReporter().hadErrors()) { 664 addError(kj::str("Internal compiler bug: Schema failed validation:\n", *exception)); 665 } 666 } 667 } 668 } 669 670 void Compiler::Node::traverse(uint eagerness, std::unordered_map<Node*, uint>& seen, 671 const SchemaLoader& finalLoader, 672 kj::Vector<schema::Node::SourceInfo::Reader>& sourceInfo) { 673 uint& slot = seen[this]; 674 if ((slot & eagerness) == eagerness) { 675 // We've already covered this node. 676 return; 677 } 678 slot |= eagerness; 679 680 KJ_IF_MAYBE(content, getContent(Content::FINISHED)) { 681 loadFinalSchema(finalLoader); 682 683 KJ_IF_MAYBE(schema, getFinalSchema()) { 684 if (eagerness / DEPENDENCIES != 0) { 685 // For traversing dependencies, discard the bits lower than DEPENDENCIES and replace 686 // them with the bits above DEPENDENCIES shifted over. 687 uint newEagerness = (eagerness & ~(DEPENDENCIES - 1)) | (eagerness / DEPENDENCIES); 688 689 traverseNodeDependencies(*schema, newEagerness, seen, finalLoader, sourceInfo); 690 for (auto& aux: content->auxSchemas) { 691 traverseNodeDependencies(aux, newEagerness, seen, finalLoader, sourceInfo); 692 } 693 } 694 } 695 696 sourceInfo.addAll(content->sourceInfo); 697 } 698 699 if (eagerness & PARENTS) { 700 KJ_IF_MAYBE(p, parent) { 701 p->traverse(eagerness, seen, finalLoader, sourceInfo); 702 } 703 } 704 705 if (eagerness & CHILDREN) { 706 KJ_IF_MAYBE(content, getContent(Content::EXPANDED)) { 707 for (auto& child: content->orderedNestedNodes) { 708 child->traverse(eagerness, seen, finalLoader, sourceInfo); 709 } 710 711 // Also traverse `using` declarations. 712 for (auto& child: content->aliases) { 713 child.second->compile(); 714 } 715 } 716 } 717 } 718 719 void Compiler::Node::traverseNodeDependencies( 720 const schema::Node::Reader& schemaNode, uint eagerness, 721 std::unordered_map<Node*, uint>& seen, 722 const SchemaLoader& finalLoader, 723 kj::Vector<schema::Node::SourceInfo::Reader>& sourceInfo) { 724 switch (schemaNode.which()) { 725 case schema::Node::STRUCT: 726 for (auto field: schemaNode.getStruct().getFields()) { 727 switch (field.which()) { 728 case schema::Field::SLOT: 729 traverseType(field.getSlot().getType(), eagerness, seen, finalLoader, sourceInfo); 730 break; 731 case schema::Field::GROUP: 732 // Aux node will be scanned later. 733 break; 734 } 735 736 traverseAnnotations(field.getAnnotations(), eagerness, seen, finalLoader, sourceInfo); 737 } 738 break; 739 740 case schema::Node::ENUM: 741 for (auto enumerant: schemaNode.getEnum().getEnumerants()) { 742 traverseAnnotations(enumerant.getAnnotations(), eagerness, seen, finalLoader, sourceInfo); 743 } 744 break; 745 746 case schema::Node::INTERFACE: { 747 auto interface = schemaNode.getInterface(); 748 for (auto superclass: interface.getSuperclasses()) { 749 uint64_t superclassId = superclass.getId(); 750 if (superclassId != 0) { // if zero, we reported an error earlier 751 traverseDependency(superclassId, eagerness, seen, finalLoader, sourceInfo); 752 } 753 traverseBrand(superclass.getBrand(), eagerness, seen, finalLoader, sourceInfo); 754 } 755 for (auto method: interface.getMethods()) { 756 traverseDependency( 757 method.getParamStructType(), eagerness, seen, finalLoader, sourceInfo, true); 758 traverseBrand(method.getParamBrand(), eagerness, seen, finalLoader, sourceInfo); 759 traverseDependency( 760 method.getResultStructType(), eagerness, seen, finalLoader, sourceInfo, true); 761 traverseBrand(method.getResultBrand(), eagerness, seen, finalLoader, sourceInfo); 762 traverseAnnotations(method.getAnnotations(), eagerness, seen, finalLoader, sourceInfo); 763 } 764 break; 765 } 766 767 case schema::Node::CONST: 768 traverseType(schemaNode.getConst().getType(), eagerness, seen, finalLoader, sourceInfo); 769 break; 770 771 case schema::Node::ANNOTATION: 772 traverseType(schemaNode.getAnnotation().getType(), eagerness, seen, finalLoader, sourceInfo); 773 break; 774 775 default: 776 break; 777 } 778 779 traverseAnnotations(schemaNode.getAnnotations(), eagerness, seen, finalLoader, sourceInfo); 780 } 781 782 void Compiler::Node::traverseType(const schema::Type::Reader& type, uint eagerness, 783 std::unordered_map<Node*, uint>& seen, 784 const SchemaLoader& finalLoader, 785 kj::Vector<schema::Node::SourceInfo::Reader>& sourceInfo) { 786 uint64_t id = 0; 787 schema::Brand::Reader brand; 788 switch (type.which()) { 789 case schema::Type::STRUCT: 790 id = type.getStruct().getTypeId(); 791 brand = type.getStruct().getBrand(); 792 break; 793 case schema::Type::ENUM: 794 id = type.getEnum().getTypeId(); 795 brand = type.getEnum().getBrand(); 796 break; 797 case schema::Type::INTERFACE: 798 id = type.getInterface().getTypeId(); 799 brand = type.getInterface().getBrand(); 800 break; 801 case schema::Type::LIST: 802 traverseType(type.getList().getElementType(), eagerness, seen, finalLoader, sourceInfo); 803 return; 804 default: 805 return; 806 } 807 808 traverseDependency(id, eagerness, seen, finalLoader, sourceInfo); 809 traverseBrand(brand, eagerness, seen, finalLoader, sourceInfo); 810 } 811 812 void Compiler::Node::traverseBrand( 813 const schema::Brand::Reader& brand, uint eagerness, 814 std::unordered_map<Node*, uint>& seen, 815 const SchemaLoader& finalLoader, 816 kj::Vector<schema::Node::SourceInfo::Reader>& sourceInfo) { 817 for (auto scope: brand.getScopes()) { 818 switch (scope.which()) { 819 case schema::Brand::Scope::BIND: 820 for (auto binding: scope.getBind()) { 821 switch (binding.which()) { 822 case schema::Brand::Binding::UNBOUND: 823 break; 824 case schema::Brand::Binding::TYPE: 825 traverseType(binding.getType(), eagerness, seen, finalLoader, sourceInfo); 826 break; 827 } 828 } 829 break; 830 case schema::Brand::Scope::INHERIT: 831 break; 832 } 833 } 834 } 835 836 void Compiler::Node::traverseDependency(uint64_t depId, uint eagerness, 837 std::unordered_map<Node*, uint>& seen, 838 const SchemaLoader& finalLoader, 839 kj::Vector<schema::Node::SourceInfo::Reader>& sourceInfo, 840 bool ignoreIfNotFound) { 841 KJ_IF_MAYBE(node, module->getCompiler().findNode(depId)) { 842 node->traverse(eagerness, seen, finalLoader, sourceInfo); 843 } else if (!ignoreIfNotFound) { 844 KJ_FAIL_ASSERT("Dependency ID not present in compiler?", depId); 845 } 846 } 847 848 void Compiler::Node::traverseAnnotations(const List<schema::Annotation>::Reader& annotations, 849 uint eagerness, 850 std::unordered_map<Node*, uint>& seen, 851 const SchemaLoader& finalLoader, 852 kj::Vector<schema::Node::SourceInfo::Reader>& sourceInfo) { 853 for (auto annotation: annotations) { 854 KJ_IF_MAYBE(node, module->getCompiler().findNode(annotation.getId())) { 855 node->traverse(eagerness, seen, finalLoader, sourceInfo); 856 } 857 } 858 } 859 860 861 void Compiler::Node::addError(kj::StringPtr error) { 862 module->getErrorReporter().addError(startByte, endByte, error); 863 } 864 865 kj::Maybe<Resolver::ResolveResult> 866 Compiler::Node::resolve(kj::StringPtr name) { 867 // Check members. 868 KJ_IF_MAYBE(member, resolveMember(name)) { 869 return *member; 870 } 871 872 // Check parameters. 873 // TODO(perf): Maintain a map? 874 auto params = declaration.getParameters(); 875 for (uint i: kj::indices(params)) { 876 if (params[i].getName() == name) { 877 ResolveResult result; 878 result.init<ResolvedParameter>(ResolvedParameter {id, i}); 879 return result; 880 } 881 } 882 883 // Check parent scope. 884 KJ_IF_MAYBE(p, parent) { 885 return p->resolve(name); 886 } else KJ_IF_MAYBE(b, module->getCompiler().lookupBuiltin(name)) { 887 ResolveResult result; 888 result.init<ResolvedDecl>(ResolvedDecl { b->id, b->genericParamCount, 0, b->kind, b, nullptr }); 889 return result; 890 } else { 891 return nullptr; 892 } 893 } 894 895 kj::Maybe<Resolver::ResolveResult> 896 Compiler::Node::resolveMember(kj::StringPtr name) { 897 if (isBuiltin) return nullptr; 898 899 KJ_IF_MAYBE(content, getContent(Content::EXPANDED)) { 900 { 901 auto iter = content->nestedNodes.find(name); 902 if (iter != content->nestedNodes.end()) { 903 Node* node = iter->second; 904 ResolveResult result; 905 result.init<ResolvedDecl>(ResolvedDecl { 906 node->id, node->genericParamCount, id, node->kind, node, nullptr }); 907 return result; 908 } 909 } 910 { 911 auto iter = content->aliases.find(name); 912 if (iter != content->aliases.end()) { 913 return iter->second->compile(); 914 } 915 } 916 } 917 return nullptr; 918 } 919 920 Resolver::ResolvedDecl Compiler::Node::resolveBuiltin(Declaration::Which which) { 921 auto& b = module->getCompiler().getBuiltin(which); 922 return { b.id, b.genericParamCount, 0, b.kind, &b, nullptr }; 923 } 924 925 Resolver::ResolvedDecl Compiler::Node::resolveId(uint64_t id) { 926 auto& n = KJ_ASSERT_NONNULL(module->getCompiler().findNode(id)); 927 uint64_t parentId = n.parent.map([](Node& n) { return n.id; }).orDefault(0); 928 return { n.id, n.genericParamCount, parentId, n.kind, &n, nullptr }; 929 } 930 931 kj::Maybe<Resolver::ResolvedDecl> Compiler::Node::getParent() { 932 return parent.map([](Node& parent) { 933 uint64_t scopeId = parent.parent.map([](Node& gp) { return gp.id; }).orDefault(0); 934 return ResolvedDecl { parent.id, parent.genericParamCount, scopeId, parent.kind, &parent, nullptr }; 935 }); 936 } 937 938 Resolver::ResolvedDecl Compiler::Node::getTopScope() { 939 Node& node = module->getRootNode(); 940 return ResolvedDecl { node.id, 0, 0, node.kind, &node, nullptr }; 941 } 942 943 kj::Maybe<Schema> Compiler::Node::resolveBootstrapSchema( 944 uint64_t id, schema::Brand::Reader brand) { 945 KJ_IF_MAYBE(node, module->getCompiler().findNode(id)) { 946 // Make sure the bootstrap schema is loaded into the SchemaLoader. 947 if (node->getBootstrapSchema() == nullptr) { 948 return nullptr; 949 } 950 951 // Now we actually invoke get() to evaluate the brand. 952 return module->getCompiler().getWorkspace().bootstrapLoader.get(id, brand); 953 } else { 954 KJ_FAIL_REQUIRE("Tried to get schema for ID we haven't seen before."); 955 } 956 } 957 958 kj::Maybe<schema::Node::Reader> Compiler::Node::resolveFinalSchema(uint64_t id) { 959 KJ_IF_MAYBE(node, module->getCompiler().findNode(id)) { 960 return node->getFinalSchema(); 961 } else { 962 KJ_FAIL_REQUIRE("Tried to get schema for ID we haven't seen before."); 963 } 964 } 965 966 kj::Maybe<Resolver::ResolvedDecl> 967 Compiler::Node::resolveImport(kj::StringPtr name) { 968 KJ_IF_MAYBE(m, module->importRelative(name)) { 969 Node& root = m->getRootNode(); 970 return ResolvedDecl { root.id, 0, 0, root.kind, &root, nullptr }; 971 } else { 972 return nullptr; 973 } 974 } 975 976 kj::Maybe<kj::Array<const byte>> Compiler::Node::readEmbed(kj::StringPtr name) { 977 return module->embedRelative(name); 978 } 979 980 kj::Maybe<Type> Compiler::Node::resolveBootstrapType(schema::Type::Reader type, Schema scope) { 981 // TODO(someday): Arguably should return null if the type or its dependencies are placeholders. 982 983 kj::Maybe<Type> result; 984 KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]() { 985 result = module->getCompiler().getWorkspace().bootstrapLoader.getType(type, scope); 986 })) { 987 result = nullptr; 988 if (!module->getErrorReporter().hadErrors()) { 989 addError(kj::str("Internal compiler bug: Bootstrap schema failed to load:\n", 990 *exception)); 991 } 992 } 993 return result; 994 } 995 996 // ======================================================================================= 997 998 Compiler::CompiledModule::CompiledModule(Compiler::Impl& compiler, Module& parserModule) 999 : compiler(compiler), parserModule(parserModule), 1000 content(parserModule.loadContent(contentArena.getOrphanage())), 1001 rootNode(*this) {} 1002 1003 kj::Maybe<Compiler::CompiledModule&> Compiler::CompiledModule::importRelative( 1004 kj::StringPtr importPath) { 1005 return parserModule.importRelative(importPath).map( 1006 [this](Module& module) -> Compiler::CompiledModule& { 1007 return compiler.addInternal(module); 1008 }); 1009 } 1010 1011 kj::Maybe<kj::Array<const byte>> Compiler::CompiledModule::embedRelative(kj::StringPtr embedPath) { 1012 return parserModule.embedRelative(embedPath); 1013 } 1014 1015 static void findImports(Expression::Reader exp, std::set<kj::StringPtr>& output) { 1016 switch (exp.which()) { 1017 case Expression::UNKNOWN: 1018 case Expression::POSITIVE_INT: 1019 case Expression::NEGATIVE_INT: 1020 case Expression::FLOAT: 1021 case Expression::STRING: 1022 case Expression::BINARY: 1023 case Expression::RELATIVE_NAME: 1024 case Expression::ABSOLUTE_NAME: 1025 case Expression::EMBED: 1026 break; 1027 1028 case Expression::IMPORT: 1029 output.insert(exp.getImport().getValue()); 1030 break; 1031 1032 case Expression::LIST: 1033 for (auto element: exp.getList()) { 1034 findImports(element, output); 1035 } 1036 break; 1037 1038 case Expression::TUPLE: 1039 for (auto element: exp.getTuple()) { 1040 findImports(element.getValue(), output); 1041 } 1042 break; 1043 1044 case Expression::APPLICATION: { 1045 auto app = exp.getApplication(); 1046 findImports(app.getFunction(), output); 1047 for (auto param: app.getParams()) { 1048 findImports(param.getValue(), output); 1049 } 1050 break; 1051 } 1052 1053 case Expression::MEMBER: { 1054 findImports(exp.getMember().getParent(), output); 1055 break; 1056 } 1057 } 1058 } 1059 1060 static void findImports(Declaration::ParamList::Reader paramList, std::set<kj::StringPtr>& output) { 1061 switch (paramList.which()) { 1062 case Declaration::ParamList::NAMED_LIST: 1063 for (auto param: paramList.getNamedList()) { 1064 findImports(param.getType(), output); 1065 for (auto ann: param.getAnnotations()) { 1066 findImports(ann.getName(), output); 1067 } 1068 } 1069 break; 1070 case Declaration::ParamList::TYPE: 1071 findImports(paramList.getType(), output); 1072 break; 1073 case Declaration::ParamList::STREAM: 1074 output.insert("/capnp/stream.capnp"); 1075 break; 1076 } 1077 } 1078 1079 static void findImports(Declaration::Reader decl, std::set<kj::StringPtr>& output) { 1080 switch (decl.which()) { 1081 case Declaration::USING: 1082 findImports(decl.getUsing().getTarget(), output); 1083 break; 1084 case Declaration::CONST: 1085 findImports(decl.getConst().getType(), output); 1086 break; 1087 case Declaration::FIELD: 1088 findImports(decl.getField().getType(), output); 1089 break; 1090 case Declaration::INTERFACE: 1091 for (auto superclass: decl.getInterface().getSuperclasses()) { 1092 findImports(superclass, output); 1093 } 1094 break; 1095 case Declaration::METHOD: { 1096 auto method = decl.getMethod(); 1097 1098 findImports(method.getParams(), output); 1099 if (method.getResults().isExplicit()) { 1100 findImports(method.getResults().getExplicit(), output); 1101 } 1102 break; 1103 } 1104 default: 1105 break; 1106 } 1107 1108 for (auto ann: decl.getAnnotations()) { 1109 findImports(ann.getName(), output); 1110 } 1111 1112 for (auto nested: decl.getNestedDecls()) { 1113 findImports(nested, output); 1114 } 1115 } 1116 1117 Orphan<List<schema::CodeGeneratorRequest::RequestedFile::Import>> 1118 Compiler::CompiledModule::getFileImportTable(Orphanage orphanage) { 1119 // Build a table of imports for CodeGeneratorRequest.RequestedFile.imports. Note that we only 1120 // care about type imports, not constant value imports, since constant values (including default 1121 // values) are already embedded in full in the schema. In other words, we only need the imports 1122 // that would need to be #included in the generated code. 1123 1124 std::set<kj::StringPtr> importNames; 1125 findImports(content.getReader().getRoot(), importNames); 1126 1127 auto result = orphanage.newOrphan<List<schema::CodeGeneratorRequest::RequestedFile::Import>>( 1128 importNames.size()); 1129 auto builder = result.get(); 1130 1131 uint i = 0; 1132 for (auto name: importNames) { 1133 // We presumably ran this import before, so it shouldn't throw now. 1134 auto entry = builder[i++]; 1135 entry.setId(KJ_ASSERT_NONNULL(importRelative(name)).rootNode.getId()); 1136 entry.setName(name); 1137 } 1138 1139 return result; 1140 } 1141 1142 // ======================================================================================= 1143 1144 Compiler::Impl::Impl(AnnotationFlag annotationFlag) 1145 : annotationFlag(annotationFlag), workspace(*this) { 1146 // Reflectively interpret the members of Declaration.body. Any member prefixed by "builtin" 1147 // defines a builtin declaration visible in the global scope. 1148 1149 StructSchema declSchema = Schema::from<Declaration>(); 1150 for (auto field: declSchema.getFields()) { 1151 auto fieldProto = field.getProto(); 1152 if (fieldProto.getDiscriminantValue() != schema::Field::NO_DISCRIMINANT) { 1153 auto name = fieldProto.getName(); 1154 if (name.startsWith("builtin")) { 1155 kj::StringPtr symbolName = name.slice(strlen("builtin")); 1156 1157 List<Declaration::BrandParameter>::Reader params; 1158 for (auto annotation: fieldProto.getAnnotations()) { 1159 if (annotation.getId() == 0x94099c3f9eb32d6bull) { 1160 params = annotation.getValue().getList().getAs<List<Declaration::BrandParameter>>(); 1161 break; 1162 } 1163 } 1164 1165 Declaration::Which which = 1166 static_cast<Declaration::Which>(fieldProto.getDiscriminantValue()); 1167 kj::Own<Node> newNode = nodeArena.allocateOwn<Node>(symbolName, which, params); 1168 builtinDeclsByKind[which] = newNode; 1169 builtinDecls[symbolName] = kj::mv(newNode); 1170 } 1171 } 1172 } 1173 } 1174 1175 Compiler::Impl::~Impl() noexcept(false) {} 1176 1177 void Compiler::Impl::clearWorkspace() { 1178 // Make sure we reconstruct the workspace even if destroying it throws an exception. 1179 KJ_DEFER(kj::ctor(workspace, *this)); 1180 kj::dtor(workspace); 1181 } 1182 1183 Compiler::CompiledModule& Compiler::Impl::addInternal(Module& parsedModule) { 1184 kj::Own<CompiledModule>& slot = modules[&parsedModule]; 1185 if (slot.get() == nullptr) { 1186 slot = kj::heap<CompiledModule>(*this, parsedModule); 1187 } 1188 1189 return *slot; 1190 } 1191 1192 uint64_t Compiler::Impl::addNode(uint64_t desiredId, Node& node) { 1193 for (;;) { 1194 auto insertResult = nodesById.insert(std::make_pair(desiredId, &node)); 1195 if (insertResult.second) { 1196 return desiredId; 1197 } 1198 1199 // Only report an error if this ID is not bogus. Actual IDs specified in the original source 1200 // code are required to have the upper bit set. Anything else must have been manufactured 1201 // at some point to cover up an error. 1202 if (desiredId & (1ull << 63)) { 1203 node.addError(kj::str("Duplicate ID @0x", kj::hex(desiredId), ".")); 1204 insertResult.first->second->addError( 1205 kj::str("ID @0x", kj::hex(desiredId), " originally used here.")); 1206 } 1207 1208 // Assign a new bogus ID. 1209 desiredId = nextBogusId++; 1210 } 1211 } 1212 1213 kj::Maybe<Compiler::Node&> Compiler::Impl::findNode(uint64_t id) { 1214 auto iter = nodesById.find(id); 1215 if (iter == nodesById.end()) { 1216 return nullptr; 1217 } else { 1218 return *iter->second; 1219 } 1220 } 1221 1222 kj::Maybe<Compiler::Node&> Compiler::Impl::lookupBuiltin(kj::StringPtr name) { 1223 auto iter = builtinDecls.find(name); 1224 if (iter == builtinDecls.end()) { 1225 return nullptr; 1226 } else { 1227 return *iter->second; 1228 } 1229 } 1230 1231 Compiler::Node& Compiler::Impl::getBuiltin(Declaration::Which which) { 1232 auto iter = builtinDeclsByKind.find(which); 1233 KJ_REQUIRE(iter != builtinDeclsByKind.end(), "invalid builtin", (uint)which); 1234 return *iter->second; 1235 } 1236 1237 kj::Maybe<uint64_t> Compiler::Impl::lookup(uint64_t parent, kj::StringPtr childName) { 1238 // Looking up members does not use the workspace, so we don't need to lock it. 1239 KJ_IF_MAYBE(parentNode, findNode(parent)) { 1240 KJ_IF_MAYBE(child, parentNode->resolveMember(childName)) { 1241 if (child->is<Resolver::ResolvedDecl>()) { 1242 return child->get<Resolver::ResolvedDecl>().id; 1243 } else { 1244 // An alias. We don't support looking up aliases with this method. 1245 return nullptr; 1246 } 1247 } else { 1248 return nullptr; 1249 } 1250 } else { 1251 KJ_FAIL_REQUIRE("lookup()s parameter 'parent' must be a known ID.", parent); 1252 } 1253 } 1254 1255 kj::Maybe<schema::Node::SourceInfo::Reader> Compiler::Impl::getSourceInfo(uint64_t id) { 1256 auto iter = sourceInfoById.find(id); 1257 if (iter == sourceInfoById.end()) { 1258 return nullptr; 1259 } else { 1260 return iter->second; 1261 } 1262 } 1263 1264 Orphan<List<schema::CodeGeneratorRequest::RequestedFile::Import>> 1265 Compiler::Impl::getFileImportTable(Module& module, Orphanage orphanage) { 1266 return addInternal(module).getFileImportTable(orphanage); 1267 } 1268 1269 Orphan<List<schema::Node::SourceInfo>> Compiler::Impl::getAllSourceInfo(Orphanage orphanage) { 1270 auto result = orphanage.newOrphan<List<schema::Node::SourceInfo>>(sourceInfoById.size()); 1271 1272 auto builder = result.get(); 1273 size_t i = 0; 1274 for (auto& entry: sourceInfoById) { 1275 builder.setWithCaveats(i++, entry.second); 1276 } 1277 1278 return result; 1279 } 1280 1281 void Compiler::Impl::eagerlyCompile(uint64_t id, uint eagerness, 1282 const SchemaLoader& finalLoader) { 1283 KJ_IF_MAYBE(node, findNode(id)) { 1284 std::unordered_map<Node*, uint> seen; 1285 kj::Vector<schema::Node::SourceInfo::Reader> sourceInfos; 1286 node->traverse(eagerness, seen, finalLoader, sourceInfos); 1287 1288 // Copy the SourceInfo structures into permanent space so that they aren't invalidated when 1289 // clearWorkspace() is called. 1290 for (auto& sourceInfo: sourceInfos) { 1291 auto words = nodeArena.allocateArray<word>(sourceInfo.totalSize().wordCount + 1); 1292 memset(words.begin(), 0, words.asBytes().size()); 1293 copyToUnchecked(sourceInfo, words); 1294 sourceInfoById.insert(std::make_pair(sourceInfo.getId(), 1295 readMessageUnchecked<schema::Node::SourceInfo>(words.begin()))); 1296 } 1297 } else { 1298 KJ_FAIL_REQUIRE("id did not come from this Compiler.", id); 1299 } 1300 } 1301 1302 void Compiler::Impl::load(const SchemaLoader& loader, uint64_t id) const { 1303 // We know that this load() is only called from the bootstrap loader which is already protected 1304 // by our mutex, so we can drop thread-safety. 1305 auto& self = const_cast<Compiler::Impl&>(*this); 1306 1307 KJ_IF_MAYBE(node, self.findNode(id)) { 1308 node->getBootstrapSchema(); 1309 } 1310 } 1311 1312 void Compiler::Impl::loadFinal(const SchemaLoader& loader, uint64_t id) { 1313 KJ_IF_MAYBE(node, findNode(id)) { 1314 node->loadFinalSchema(loader); 1315 } 1316 } 1317 1318 // ======================================================================================= 1319 1320 Compiler::Compiler(AnnotationFlag annotationFlag) 1321 : impl(kj::heap<Impl>(annotationFlag)), 1322 loader(*this) {} 1323 Compiler::~Compiler() noexcept(false) {} 1324 1325 Compiler::ModuleScope Compiler::add(Module& module) const { 1326 Node& root = impl.lockExclusive()->get()->addInternal(module).getRootNode(); 1327 return ModuleScope(*this, root.getId(), root); 1328 } 1329 1330 kj::Maybe<uint64_t> Compiler::lookup(uint64_t parent, kj::StringPtr childName) const { 1331 return impl.lockExclusive()->get()->lookup(parent, childName); 1332 } 1333 1334 kj::Maybe<schema::Node::SourceInfo::Reader> Compiler::getSourceInfo(uint64_t id) const { 1335 return impl.lockExclusive()->get()->getSourceInfo(id); 1336 } 1337 1338 Orphan<List<schema::CodeGeneratorRequest::RequestedFile::Import>> 1339 Compiler::getFileImportTable(Module& module, Orphanage orphanage) const { 1340 return impl.lockExclusive()->get()->getFileImportTable(module, orphanage); 1341 } 1342 1343 Orphan<List<schema::Node::SourceInfo>> Compiler::getAllSourceInfo(Orphanage orphanage) const { 1344 return impl.lockExclusive()->get()->getAllSourceInfo(orphanage); 1345 } 1346 1347 void Compiler::eagerlyCompile(uint64_t id, uint eagerness) const { 1348 impl.lockExclusive()->get()->eagerlyCompile(id, eagerness, loader); 1349 } 1350 1351 void Compiler::clearWorkspace() const { 1352 impl.lockExclusive()->get()->clearWorkspace(); 1353 } 1354 1355 void Compiler::load(const SchemaLoader& loader, uint64_t id) const { 1356 impl.lockExclusive()->get()->loadFinal(loader, id); 1357 } 1358 1359 // ----------------------------------------------------------------------------- 1360 1361 class Compiler::ErrorIgnorer: public ErrorReporter { 1362 public: 1363 void addError(uint32_t startByte, uint32_t endByte, kj::StringPtr message) override {} 1364 bool hadErrors() override { return false; } 1365 1366 static ErrorIgnorer instance; 1367 }; 1368 Compiler::ErrorIgnorer Compiler::ErrorIgnorer::instance; 1369 1370 kj::Maybe<Type> Compiler::CompiledType::getSchema() { 1371 capnp::word scratch[32]; 1372 memset(&scratch, 0, sizeof(scratch)); 1373 capnp::MallocMessageBuilder message(scratch); 1374 auto builder = message.getRoot<schema::Type>(); 1375 1376 { 1377 auto lock = compiler.impl.lockShared(); 1378 decl.get(lock).compileAsType(ErrorIgnorer::instance, builder); 1379 } 1380 1381 // No need to pass `scope` as second parameter since CompiledType always represents a type 1382 // expression evaluated free-standing, not in any scope. 1383 return compiler.loader.getType(builder.asReader()); 1384 } 1385 1386 Compiler::CompiledType Compiler::CompiledType::clone() { 1387 kj::ExternalMutexGuarded<BrandedDecl> newDecl; 1388 { 1389 auto lock = compiler.impl.lockExclusive(); 1390 newDecl.set(lock, kj::cp(decl.get(lock))); 1391 } 1392 return CompiledType(compiler, kj::mv(newDecl)); 1393 } 1394 1395 kj::Maybe<Compiler::CompiledType> Compiler::CompiledType::getMember(kj::StringPtr name) { 1396 kj::ExternalMutexGuarded<BrandedDecl> newDecl; 1397 bool found = false; 1398 1399 { 1400 auto lock = compiler.impl.lockShared(); 1401 KJ_IF_MAYBE(member, decl.get(lock).getMember(name, {})) { 1402 newDecl.set(lock, kj::mv(*member)); 1403 found = true; 1404 } 1405 } 1406 1407 if (found) { 1408 return CompiledType(compiler, kj::mv(newDecl)); 1409 } else { 1410 return nullptr; 1411 } 1412 } 1413 1414 kj::Maybe<Compiler::CompiledType> Compiler::CompiledType::applyBrand( 1415 kj::Array<CompiledType> arguments) { 1416 kj::ExternalMutexGuarded<BrandedDecl> newDecl; 1417 bool found = false; 1418 1419 { 1420 auto lock = compiler.impl.lockShared(); 1421 auto args = KJ_MAP(arg, arguments) { return kj::mv(arg.decl.get(lock)); }; 1422 KJ_IF_MAYBE(member, decl.get(lock).applyParams(kj::mv(args), {})) { 1423 newDecl.set(lock, kj::mv(*member)); 1424 found = true; 1425 } 1426 } 1427 1428 if (found) { 1429 return CompiledType(compiler, kj::mv(newDecl)); 1430 } else { 1431 return nullptr; 1432 } 1433 } 1434 1435 Compiler::CompiledType Compiler::ModuleScope::getRoot() { 1436 kj::ExternalMutexGuarded<BrandedDecl> newDecl; 1437 1438 { 1439 auto lock = compiler.impl.lockExclusive(); 1440 auto brandScope = kj::refcounted<BrandScope>(ErrorIgnorer::instance, node.getId(), 0, node); 1441 Resolver::ResolvedDecl decl { node.getId(), 0, 0, node.getKind(), &node, nullptr }; 1442 newDecl.set(lock, BrandedDecl(kj::mv(decl), kj::mv(brandScope), {})); 1443 } 1444 1445 return CompiledType(compiler, kj::mv(newDecl)); 1446 } 1447 1448 kj::Maybe<Compiler::CompiledType> Compiler::ModuleScope::evalType( 1449 Expression::Reader expression, ErrorReporter& errorReporter) { 1450 kj::ExternalMutexGuarded<BrandedDecl> newDecl; 1451 bool found = false; 1452 1453 { 1454 auto lock = compiler.impl.lockExclusive(); 1455 auto brandScope = kj::refcounted<BrandScope>(errorReporter, node.getId(), 0, node); 1456 KJ_IF_MAYBE(result, brandScope->compileDeclExpression( 1457 expression, node, ImplicitParams::none())) { 1458 newDecl.set(lock, kj::mv(*result)); 1459 found = true; 1460 }; 1461 } 1462 1463 if (found) { 1464 return CompiledType(compiler, kj::mv(newDecl)); 1465 } else { 1466 return nullptr; 1467 } 1468 } 1469 1470 } // namespace compiler 1471 } // namespace capnp