compiler.c++ 44.1 KB
Newer Older
Kenton Varda's avatar
Kenton Varda committed
1 2
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
Kenton Varda's avatar
Kenton Varda committed
3
//
Kenton Varda's avatar
Kenton Varda committed
4 5 6 7 8 9
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
Kenton Varda's avatar
Kenton Varda committed
10
//
Kenton Varda's avatar
Kenton Varda committed
11 12
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
Kenton Varda's avatar
Kenton Varda committed
13
//
Kenton Varda's avatar
Kenton Varda committed
14 15 16 17 18 19 20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
Kenton Varda's avatar
Kenton Varda committed
21 22

#include "compiler.h"
Kenton Varda's avatar
Kenton Varda committed
23
#include "parser.h"      // only for generateChildId()
Kenton Varda's avatar
Kenton Varda committed
24 25 26 27 28 29
#include <kj/mutex.h>
#include <kj/arena.h>
#include <kj/vector.h>
#include <kj/debug.h>
#include <capnp/message.h>
#include <map>
Kenton Varda's avatar
Kenton Varda committed
30
#include <set>
Kenton Varda's avatar
Kenton Varda committed
31 32 33 34 35 36 37 38 39
#include <unordered_map>
#include "node-translator.h"
#include "md5.h"

namespace capnp {
namespace compiler {

class Compiler::Alias {
public:
40 41
  Alias(CompiledModule& module, Node& parent, const Expression::Reader& targetName)
      : module(module), parent(parent), targetName(targetName) {}
Kenton Varda's avatar
Kenton Varda committed
42

43
  kj::Maybe<NodeTranslator::Resolver::ResolveResult> compile();
Kenton Varda's avatar
Kenton Varda committed
44 45

private:
46 47
  CompiledModule& module;
  Node& parent;
Kenton Varda's avatar
Kenton Varda committed
48
  Expression::Reader targetName;
49 50 51
  kj::Maybe<NodeTranslator::Resolver::ResolveResult> target;
  Orphan<schema::Brand> brandOrphan;
  bool initialized = false;
Kenton Varda's avatar
Kenton Varda committed
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
};

class Compiler::Node: public NodeTranslator::Resolver {
  // Passes through four states:
  // - Stub:  On initial construction, the Node is just a placeholder object.  Its ID has been
  //     determined, and it is placed in its parent's member table as well as the compiler's
  //     nodes-by-ID table.
  // - Expanded:  Nodes have been constructed for all of this Node's nested children.  This happens
  //     the first time a lookup is performed for one of those children.
  // - Bootstrap:  A NodeTranslator has been built and advanced to the bootstrap phase.
  // - Finished:  A final Schema object has been constructed.

public:
  explicit Node(CompiledModule& module);
  // Create a root node representing the given file.  May

68
  Node(Node& parent, const Declaration::Reader& declaration);
Kenton Varda's avatar
Kenton Varda committed
69 70
  // Create a child node.

Kenton Varda's avatar
Kenton Varda committed
71
  Node(kj::StringPtr name, Declaration::Which kind,
72
       List<Declaration::BrandParameter>::Reader genericParams);
Kenton Varda's avatar
Kenton Varda committed
73 74
  // Create a dummy node representing a built-in declaration, like "Int32" or "true".

75
  uint64_t getId() { return id; }
76
  uint getParameterCount() { return genericParamCount; }
77
  Declaration::Which getKind() { return kind; }
Kenton Varda's avatar
Kenton Varda committed
78

79 80 81
  kj::Maybe<Schema> getBootstrapSchema();
  kj::Maybe<schema::Node::Reader> getFinalSchema();
  void loadFinalSchema(const SchemaLoader& loader);
82

83 84
  void traverse(uint eagerness, std::unordered_map<Node*, uint>& seen,
                const SchemaLoader& finalLoader);
85 86
  // Get the final schema for this node, and also possibly traverse the node's children and
  // dependencies to ensure that they are loaded, depending on the mode.
Kenton Varda's avatar
Kenton Varda committed
87

88
  void addError(kj::StringPtr error);
Kenton Varda's avatar
Kenton Varda committed
89 90 91
  // Report an error on this Node.

  // implements NodeTranslator::Resolver -----------------------------
92 93 94 95
  kj::Maybe<ResolveResult> resolve(kj::StringPtr name) override;
  kj::Maybe<ResolveResult> resolveMember(kj::StringPtr name) override;
  ResolvedDecl resolveBuiltin(Declaration::Which which) override;
  ResolvedDecl resolveId(uint64_t id) override;
96
  kj::Maybe<ResolvedDecl> getParent() override;
Kenton Varda's avatar
Kenton Varda committed
97
  ResolvedDecl getTopScope() override;
98
  kj::Maybe<Schema> resolveBootstrapSchema(
99
      uint64_t id, schema::Brand::Reader brand) override;
100
  kj::Maybe<schema::Node::Reader> resolveFinalSchema(uint64_t id) override;
Kenton Varda's avatar
Kenton Varda committed
101
  kj::Maybe<ResolvedDecl> resolveImport(kj::StringPtr name) override;
102
  kj::Maybe<Type> resolveBootstrapType(schema::Type::Reader type, Schema scope) override;
Kenton Varda's avatar
Kenton Varda committed
103 104

private:
105 106
  CompiledModule* module;  // null iff isBuiltin is true
  kj::Maybe<Node&> parent;
Kenton Varda's avatar
Kenton Varda committed
107 108 109 110 111 112 113 114 115 116 117 118 119

  Declaration::Reader declaration;
  // AST of the declaration parsed from the schema file.  May become invalid once the content
  // state has reached FINISHED.

  uint64_t id;
  // The ID of this node, either taken from the AST or computed based on the parent.  Or, a dummy
  // value, if duplicates were detected.

  kj::StringPtr displayName;
  // Fully-qualified display name for this node.  For files, this is just the file name, otherwise
  // it is "filename:Path.To.Decl".

120
  Declaration::Which kind;
Kenton Varda's avatar
Kenton Varda committed
121 122
  // Kind of node.

Kenton Varda's avatar
Kenton Varda committed
123 124 125
  uint genericParamCount;
  // Number of generic parameters.

Kenton Varda's avatar
Kenton Varda committed
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
  bool isBuiltin;
  // Whether this is a bulit-in declaration, like "Int32" or "true".

  uint32_t startByte;
  uint32_t endByte;
  // Start and end byte for reporting general errors.

  struct Content {
    inline Content(): state(STUB) {}

    enum State {
      STUB,
      EXPANDED,
      BOOTSTRAP,
      FINISHED
    };
    State state;
143
    // Indicates which fields below are valid.
Kenton Varda's avatar
Kenton Varda committed
144

145 146
    inline bool stateHasReached(State minimumState) {
      return state >= minimumState;
Kenton Varda's avatar
Kenton Varda committed
147 148
    }
    inline void advanceState(State newState) {
149
      state = newState;
Kenton Varda's avatar
Kenton Varda committed
150 151 152 153 154 155
    }

    // EXPANDED ------------------------------------

    typedef std::multimap<kj::StringPtr, kj::Own<Node>> NestedNodesMap;
    NestedNodesMap nestedNodes;
156
    kj::Vector<Node*> orderedNestedNodes;
Kenton Varda's avatar
Kenton Varda committed
157 158
    // multimap in case of duplicate member names -- we still want to compile them, even if it's an
    // error.
Kenton Varda's avatar
Kenton Varda committed
159 160 161

    typedef std::multimap<kj::StringPtr, kj::Own<Alias>> AliasMap;
    AliasMap aliases;
Kenton Varda's avatar
Kenton Varda committed
162
    // The "using" declarations.  These are just links to nodes elsewhere.
Kenton Varda's avatar
Kenton Varda committed
163 164 165 166 167 168

    // BOOTSTRAP -----------------------------------

    NodeTranslator* translator;
    // Node translator, allocated in the bootstrap arena.

169 170
    kj::Maybe<Schema> bootstrapSchema;
    // The schema built in the bootstrap loader.  Null if the bootstrap loader threw an exception.
Kenton Varda's avatar
Kenton Varda committed
171 172 173

    // FINISHED ------------------------------------

174 175
    kj::Maybe<schema::Node::Reader> finalSchema;
    // The completed schema, ready to load into the real schema loader.
Kenton Varda's avatar
Kenton Varda committed
176

177
    kj::Array<schema::Node::Reader> auxSchemas;
Kenton Varda's avatar
Kenton Varda committed
178
    // Schemas for all auxiliary nodes built by the NodeTranslator.
Kenton Varda's avatar
Kenton Varda committed
179 180
  };

181 182
  Content guardedContent;     // Read using getContent() only!
  bool inGetContent = false;  // True while getContent() is running; detects cycles.
Kenton Varda's avatar
Kenton Varda committed
183

Kenton Varda's avatar
Kenton Varda committed
184 185 186 187
  kj::Maybe<schema::Node::Reader> loadedFinalSchema;
  // Copy of `finalSchema` as loaded into the final schema loader.  This doesn't go away if the
  // workspace is destroyed.

Kenton Varda's avatar
Kenton Varda committed
188 189 190 191 192 193 194
  // ---------------------------------------------

  static uint64_t generateId(uint64_t parentId, kj::StringPtr declName,
                             Declaration::Id::Reader declId);
  // Extract the ID from the declaration, or if it has none, generate one based on the name and
  // parent ID.

195
  static kj::StringPtr joinDisplayName(kj::Arena& arena, Node& parent, kj::StringPtr declName);
Kenton Varda's avatar
Kenton Varda committed
196 197 198
  // Join the parent's display name with the child's unqualified name to construct the child's
  // display name.

199 200 201 202
  kj::Maybe<Content&> getContent(Content::State minimumState);
  // Advances the content to at least the given state and returns it.  Returns null if getContent()
  // is being called recursively and the given state has not yet been reached, as this indicates
  // that the declaration recursively depends on itself.
203

Kenton Varda's avatar
Kenton Varda committed
204
  void traverseNodeDependencies(const schema::Node::Reader& schemaNode, uint eagerness,
205 206
                                std::unordered_map<Node*, uint>& seen,
                                const SchemaLoader& finalLoader);
Kenton Varda's avatar
Kenton Varda committed
207
  void traverseType(const schema::Type::Reader& type, uint eagerness,
208 209
                    std::unordered_map<Node*, uint>& seen,
                    const SchemaLoader& finalLoader);
210 211 212
  void traverseBrand(const schema::Brand::Reader& brand, uint eagerness,
                     std::unordered_map<Node*, uint>& seen,
                     const SchemaLoader& finalLoader);
Kenton Varda's avatar
Kenton Varda committed
213
  void traverseAnnotations(const List<schema::Annotation>::Reader& annotations, uint eagerness,
214 215
                           std::unordered_map<Node*, uint>& seen,
                           const SchemaLoader& finalLoader);
216
  void traverseDependency(uint64_t depId, uint eagerness,
217 218 219
                          std::unordered_map<Node*, uint>& seen,
                          const SchemaLoader& finalLoader,
                          bool ignoreIfNotFound = false);
220
  // Helpers for traverse().
Kenton Varda's avatar
Kenton Varda committed
221 222 223 224
};

class Compiler::CompiledModule {
public:
225
  CompiledModule(Compiler::Impl& compiler, Module& parserModule);
Kenton Varda's avatar
Kenton Varda committed
226

227
  Compiler::Impl& getCompiler() { return compiler; }
Kenton Varda's avatar
Kenton Varda committed
228

229 230 231 232
  ErrorReporter& getErrorReporter() { return parserModule; }
  ParsedFile::Reader getParsedFile() { return content.getReader(); }
  Node& getRootNode() { return rootNode; }
  kj::StringPtr getSourceName() { return parserModule.getSourceName(); }
Kenton Varda's avatar
Kenton Varda committed
233

234
  kj::Maybe<CompiledModule&> importRelative(kj::StringPtr importPath);
Kenton Varda's avatar
Kenton Varda committed
235

Kenton Varda's avatar
Kenton Varda committed
236
  Orphan<List<schema::CodeGeneratorRequest::RequestedFile::Import>>
237
      getFileImportTable(Orphanage orphanage);
Kenton Varda's avatar
Kenton Varda committed
238

Kenton Varda's avatar
Kenton Varda committed
239
private:
240 241
  Compiler::Impl& compiler;
  Module& parserModule;
Kenton Varda's avatar
Kenton Varda committed
242
  MallocMessageBuilder contentArena;
243
  Orphan<ParsedFile> content;
Kenton Varda's avatar
Kenton Varda committed
244 245 246 247 248
  Node rootNode;
};

class Compiler::Impl: public SchemaLoader::LazyLoadCallback {
public:
249
  explicit Impl(AnnotationFlag annotationFlag);
250
  virtual ~Impl() noexcept(false);
Kenton Varda's avatar
Kenton Varda committed
251

252 253
  uint64_t add(Module& module);
  kj::Maybe<uint64_t> lookup(uint64_t parent, kj::StringPtr childName);
Kenton Varda's avatar
Kenton Varda committed
254
  Orphan<List<schema::CodeGeneratorRequest::RequestedFile::Import>>
255 256 257
      getFileImportTable(Module& module, Orphanage orphanage);
  void eagerlyCompile(uint64_t id, uint eagerness, const SchemaLoader& loader);
  CompiledModule& addInternal(Module& parsedModule);
Kenton Varda's avatar
Kenton Varda committed
258 259 260 261 262 263 264

  struct Workspace {
    // Scratch space where stuff can be allocated while working.  The Workspace is available
    // whenever nodes are actively being compiled, then is destroyed once control exits the
    // compiler.  Note that since nodes are compiled lazily, a new Workspace may have to be
    // constructed in order to compile more nodes later.

265
    MallocMessageBuilder message;
Kenton Varda's avatar
Kenton Varda committed
266 267 268
    Orphanage orphanage;
    // Orphanage for allocating temporary Cap'n Proto objects.

269 270 271 272 273
    kj::Arena arena;
    // Arena for allocating temporary native objects.  Note that objects in `arena` may contain
    // pointers into `message` that will be manipulated on destruction, so `arena` must be declared
    // after `message`.

Kenton Varda's avatar
Kenton Varda committed
274 275 276 277 278 279
    SchemaLoader bootstrapLoader;
    // Loader used to load bootstrap schemas.  The bootstrap schema nodes are similar to the final
    // versions except that any value expressions which depend on knowledge of other types (e.g.
    // default values for struct fields) are left unevaluated (the values in the schema are empty).
    // These bootstrap schemas can then be plugged into the dynamic API and used to evaluate these
    // remaining values.
280

281 282 283
    inline explicit Workspace(const SchemaLoader::LazyLoadCallback& loaderCallback)
        : orphanage(message.getOrphanage()),
          bootstrapLoader(loaderCallback) {}
Kenton Varda's avatar
Kenton Varda committed
284 285
  };

286
  kj::Arena& getNodeArena() { return nodeArena; }
Kenton Varda's avatar
Kenton Varda committed
287 288
  // Arena where nodes and other permanent objects should be allocated.

289
  Workspace& getWorkspace() { return workspace; }
290
  // Temporary workspace that can be used to construct bootstrap objects.
Kenton Varda's avatar
Kenton Varda committed
291

292
  inline bool shouldCompileAnnotations() {
293 294 295
    return annotationFlag == AnnotationFlag::COMPILE_ANNOTATIONS;
  }

296 297
  void clearWorkspace();
  // Reset the temporary workspace.
Kenton Varda's avatar
Kenton Varda committed
298

299
  uint64_t addNode(uint64_t desiredId, Node& node);
Kenton Varda's avatar
Kenton Varda committed
300 301 302 303
  // Add the given node to the by-ID map under the given ID.  If another node with the same ID
  // already exists, choose a new one arbitrarily and use that instead.  Return the ID that was
  // finally used.

304
  kj::Maybe<Node&> findNode(uint64_t id);
Kenton Varda's avatar
Kenton Varda committed
305

306
  kj::Maybe<Node&> lookupBuiltin(kj::StringPtr name);
307
  Node& getBuiltin(Declaration::Which which);
Kenton Varda's avatar
Kenton Varda committed
308 309

  void load(const SchemaLoader& loader, uint64_t id) const override;
310 311 312 313
  // SchemaLoader callback for the bootstrap loader.

  void loadFinal(const SchemaLoader& loader, uint64_t id);
  // Called from the SchemaLoader callback for the final loader.
Kenton Varda's avatar
Kenton Varda committed
314 315

private:
316 317
  AnnotationFlag annotationFlag;

Kenton Varda's avatar
Kenton Varda committed
318 319 320
  kj::Arena nodeArena;
  // Arena used to allocate nodes and other permanent objects.

321
  Workspace workspace;
322
  // The temporary workspace.
Kenton Varda's avatar
Kenton Varda committed
323

324
  std::unordered_map<Module*, kj::Own<CompiledModule>> modules;
Kenton Varda's avatar
Kenton Varda committed
325 326
  // Map of parser modules to compiler modules.

327
  std::unordered_map<uint64_t, Node*> nodesById;
Kenton Varda's avatar
Kenton Varda committed
328 329 330
  // Map of nodes by ID.

  std::map<kj::StringPtr, kj::Own<Node>> builtinDecls;
331
  std::map<Declaration::Which, Node*> builtinDeclsByKind;
Kenton Varda's avatar
Kenton Varda committed
332 333
  // Map of built-in declarations, like "Int32" and "List", which make up the global scope.

334 335
  uint64_t nextBogusId = 1000;
  // Counter for assigning bogus IDs to nodes whose real ID is a duplicate.
Kenton Varda's avatar
Kenton Varda committed
336 337 338 339
};

// =======================================================================================

340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
kj::Maybe<NodeTranslator::Resolver::ResolveResult> Compiler::Alias::compile() {
  if (!initialized) {
    initialized = true;

    auto& workspace = module.getCompiler().getWorkspace();
    brandOrphan = workspace.orphanage.newOrphan<schema::Brand>();

    // If the Workspace is destroyed, revert the alias to the uninitialized state, because the
    // orphan we created is no longer valid in this case.
    workspace.arena.copy(kj::defer([this]() {
      initialized = false;
      brandOrphan = Orphan<schema::Brand>();
    }));

    target = NodeTranslator::compileDecl(
        parent.getId(), parent.getParameterCount(), parent,
        module.getErrorReporter(), targetName, brandOrphan.get());
  }

  return target;
}

// =======================================================================================

Kenton Varda's avatar
Kenton Varda committed
364 365 366 367 368 369
Compiler::Node::Node(CompiledModule& module)
    : module(&module),
      parent(nullptr),
      declaration(module.getParsedFile().getRoot()),
      id(generateId(0, declaration.getName().getValue(), declaration.getId())),
      displayName(module.getSourceName()),
370
      kind(declaration.which()),
Kenton Varda's avatar
Kenton Varda committed
371
      genericParamCount(declaration.getParameters().size()),
Kenton Varda's avatar
Kenton Varda committed
372 373 374 375 376 377 378 379 380 381 382 383 384
      isBuiltin(false) {
  auto name = declaration.getName();
  if (name.getValue().size() > 0) {
    startByte = name.getStartByte();
    endByte = name.getEndByte();
  } else {
    startByte = declaration.getStartByte();
    endByte = declaration.getEndByte();
  }

  id = module.getCompiler().addNode(id, *this);
}

385
Compiler::Node::Node(Node& parent, const Declaration::Reader& declaration)
Kenton Varda's avatar
Kenton Varda committed
386 387 388 389 390 391
    : module(parent.module),
      parent(parent),
      declaration(declaration),
      id(generateId(parent.id, declaration.getName().getValue(), declaration.getId())),
      displayName(joinDisplayName(parent.module->getCompiler().getNodeArena(),
                                  parent, declaration.getName().getValue())),
392
      kind(declaration.which()),
Kenton Varda's avatar
Kenton Varda committed
393
      genericParamCount(declaration.getParameters().size()),
Kenton Varda's avatar
Kenton Varda committed
394 395 396 397 398 399 400 401 402 403 404 405 406
      isBuiltin(false) {
  auto name = declaration.getName();
  if (name.getValue().size() > 0) {
    startByte = name.getStartByte();
    endByte = name.getEndByte();
  } else {
    startByte = declaration.getStartByte();
    endByte = declaration.getEndByte();
  }

  id = module->getCompiler().addNode(id, *this);
}

Kenton Varda's avatar
Kenton Varda committed
407
Compiler::Node::Node(kj::StringPtr name, Declaration::Which kind,
408
                     List<Declaration::BrandParameter>::Reader genericParams)
Kenton Varda's avatar
Kenton Varda committed
409 410
    : module(nullptr),
      parent(nullptr),
Kenton Varda's avatar
Kenton Varda committed
411 412
      // It's helpful if these have unique IDs. Real type IDs can't be under 2^31 anyway.
      id(1000 + static_cast<uint>(kind)),
Kenton Varda's avatar
Kenton Varda committed
413 414
      displayName(name),
      kind(kind),
Kenton Varda's avatar
Kenton Varda committed
415
      genericParamCount(genericParams.size()),
Kenton Varda's avatar
Kenton Varda committed
416 417 418 419 420 421
      isBuiltin(true),
      startByte(0),
      endByte(0) {}

uint64_t Compiler::Node::generateId(uint64_t parentId, kj::StringPtr declName,
                                    Declaration::Id::Reader declId) {
422
  if (declId.isUid()) {
Kenton Varda's avatar
Kenton Varda committed
423 424 425
    return declId.getUid().getValue();
  }

Kenton Varda's avatar
Kenton Varda committed
426
  return generateChildId(parentId, declName);
Kenton Varda's avatar
Kenton Varda committed
427 428 429
}

kj::StringPtr Compiler::Node::joinDisplayName(
430
    kj::Arena& arena, Node& parent, kj::StringPtr declName) {
Kenton Varda's avatar
Kenton Varda committed
431 432 433 434 435 436 437 438
  kj::ArrayPtr<char> result = arena.allocateArray<char>(
      parent.displayName.size() + declName.size() + 2);

  size_t separatorPos = parent.displayName.size();
  memcpy(result.begin(), parent.displayName.begin(), separatorPos);
  result[separatorPos] = parent.parent == nullptr ? ':' : '.';
  memcpy(result.begin() + separatorPos + 1, declName.begin(), declName.size());
  result[result.size() - 1] = '\0';
439
  return kj::StringPtr(result.begin(), result.size() - 1);
Kenton Varda's avatar
Kenton Varda committed
440 441
}

442
kj::Maybe<Compiler::Node::Content&> Compiler::Node::getContent(Content::State minimumState) {
Kenton Varda's avatar
Kenton Varda committed
443 444
  KJ_REQUIRE(!isBuiltin, "illegal method call for built-in declaration");

445 446 447 448 449 450 451 452 453
  auto& content = guardedContent;

  if (content.stateHasReached(minimumState)) {
    return content;
  }

  if (inGetContent) {
    addError("Declaration recursively depends on itself.");
    return nullptr;
Kenton Varda's avatar
Kenton Varda committed
454 455
  }

456 457
  inGetContent = true;
  KJ_DEFER(inGetContent = false);
Kenton Varda's avatar
Kenton Varda committed
458

459
  switch (content.state) {
Kenton Varda's avatar
Kenton Varda committed
460 461 462 463 464 465 466
    case Content::STUB: {
      if (minimumState <= Content::STUB) break;

      // Expand the child nodes.
      auto& arena = module->getCompiler().getNodeArena();

      for (auto nestedDecl: declaration.getNestedDecls()) {
467 468 469 470 471 472 473
        switch (nestedDecl.which()) {
          case Declaration::FILE:
          case Declaration::CONST:
          case Declaration::ANNOTATION:
          case Declaration::ENUM:
          case Declaration::STRUCT:
          case Declaration::INTERFACE: {
Kenton Varda's avatar
Kenton Varda committed
474 475
            kj::Own<Node> subNode = arena.allocateOwn<Node>(*this, nestedDecl);
            kj::StringPtr name = nestedDecl.getName().getValue();
476 477
            content.orderedNestedNodes.add(subNode);
            content.nestedNodes.insert(std::make_pair(name, kj::mv(subNode)));
Kenton Varda's avatar
Kenton Varda committed
478 479 480
            break;
          }

481
          case Declaration::USING: {
Kenton Varda's avatar
Kenton Varda committed
482
            kj::Own<Alias> alias = arena.allocateOwn<Alias>(
483
                *module, *this, nestedDecl.getUsing().getTarget());
Kenton Varda's avatar
Kenton Varda committed
484
            kj::StringPtr name = nestedDecl.getName().getValue();
485
            content.aliases.insert(std::make_pair(name, kj::mv(alias)));
Kenton Varda's avatar
Kenton Varda committed
486 487
            break;
          }
488 489 490 491 492 493 494
          case Declaration::ENUMERANT:
          case Declaration::FIELD:
          case Declaration::UNION:
          case Declaration::GROUP:
          case Declaration::METHOD:
          case Declaration::NAKED_ID:
          case Declaration::NAKED_ANNOTATION:
Kenton Varda's avatar
Kenton Varda committed
495 496 497 498 499 500 501 502
            // Not a node.  Skip.
            break;
          default:
            KJ_FAIL_ASSERT("unknown declaration type", nestedDecl);
            break;
        }
      }

503
      content.advanceState(Content::EXPANDED);
Kenton Varda's avatar
Kenton Varda committed
504 505 506 507 508 509 510 511 512
      // no break
    }

    case Content::EXPANDED: {
      if (minimumState <= Content::EXPANDED) break;

      // Construct the NodeTranslator.
      auto& workspace = module->getCompiler().getWorkspace();

Kenton Varda's avatar
Kenton Varda committed
513
      auto schemaNode = workspace.orphanage.newOrphan<schema::Node>();
Kenton Varda's avatar
Kenton Varda committed
514 515 516
      auto builder = schemaNode.get();
      builder.setId(id);
      builder.setDisplayName(displayName);
517 518 519 520 521 522 523 524 525 526
      // TODO(cleanup):  Would be better if we could remember the prefix length from before we
      //   added this decl's name to the end.
      KJ_IF_MAYBE(lastDot, displayName.findLast('.')) {
        builder.setDisplayNamePrefixLength(*lastDot + 1);
      }
      KJ_IF_MAYBE(lastColon, displayName.findLast(':')) {
        if (*lastColon > builder.getDisplayNamePrefixLength()) {
          builder.setDisplayNamePrefixLength(*lastColon + 1);
        }
      }
Kenton Varda's avatar
Kenton Varda committed
527 528 529 530
      KJ_IF_MAYBE(p, parent) {
        builder.setScopeId(p->id);
      }

531
      auto nestedNodes = builder.initNestedNodes(content.orderedNestedNodes.size());
Kenton Varda's avatar
Kenton Varda committed
532
      auto nestedIter = nestedNodes.begin();
533
      for (auto node: content.orderedNestedNodes) {
534 535
        nestedIter->setName(node->declaration.getName().getValue());
        nestedIter->setId(node->id);
Kenton Varda's avatar
Kenton Varda committed
536 537 538
        ++nestedIter;
      }

539
      content.translator = &workspace.arena.allocate<NodeTranslator>(
540 541
          *this, module->getErrorReporter(), declaration, kj::mv(schemaNode),
          module->getCompiler().shouldCompileAnnotations());
542
      KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&](){
543
        auto nodeSet = content.translator->getBootstrapNode();
Kenton Varda's avatar
Kenton Varda committed
544 545 546
        for (auto& auxNode: nodeSet.auxNodes) {
          workspace.bootstrapLoader.loadOnce(auxNode);
        }
547
        content.bootstrapSchema = workspace.bootstrapLoader.loadOnce(nodeSet.node);
548
      })) {
549
        content.bootstrapSchema = nullptr;
550 551 552 553 554 555
        // Only bother to report validation failures if we think we haven't seen any errors.
        // Otherwise we assume that the errors caused the validation failure.
        if (!module->getErrorReporter().hadErrors()) {
          addError(kj::str("Internal compiler bug: Bootstrap schema failed validation:\n",
                           *exception));
        }
556
      }
Kenton Varda's avatar
Kenton Varda committed
557

Kenton Varda's avatar
Kenton Varda committed
558 559
      // If the Workspace is destroyed, revert the node to the EXPANDED state, because the
      // NodeTranslator is no longer valid in this case.
560 561
      workspace.arena.copy(kj::defer([&content]() {
        content.bootstrapSchema = nullptr;
Kenton Varda's avatar
Kenton Varda committed
562
        if (content.state > Content::EXPANDED) {
563
          content.state = Content::EXPANDED;
Kenton Varda's avatar
Kenton Varda committed
564 565 566
        }
      }));

567
      content.advanceState(Content::BOOTSTRAP);
Kenton Varda's avatar
Kenton Varda committed
568 569 570 571 572 573 574
      // no break
    }

    case Content::BOOTSTRAP: {
      if (minimumState <= Content::BOOTSTRAP) break;

      // Create the final schema.
575 576 577
      auto nodeSet = content.translator->finish();
      content.finalSchema = nodeSet.node;
      content.auxSchemas = kj::mv(nodeSet.auxNodes);
578

579
      content.advanceState(Content::FINISHED);
Kenton Varda's avatar
Kenton Varda committed
580 581 582 583 584 585 586
      // no break
    }

    case Content::FINISHED:
      break;
  }

587
  return content;
Kenton Varda's avatar
Kenton Varda committed
588 589
}

590
kj::Maybe<Schema> Compiler::Node::getBootstrapSchema() {
Kenton Varda's avatar
Kenton Varda committed
591 592 593 594
  KJ_IF_MAYBE(schema, loadedFinalSchema) {
    // We don't need to rebuild the bootstrap schema if we already have a final schema.
    return module->getCompiler().getWorkspace().bootstrapLoader.loadOnce(*schema);
  } else KJ_IF_MAYBE(content, getContent(Content::BOOTSTRAP)) {
595 596 597 598 599 600 601 602 603
    if (content->state == Content::FINISHED && content->bootstrapSchema == nullptr) {
      // The bootstrap schema was discarded.  Copy it from the final schema.
      // (We can't just return the final schema because using it could trigger schema loader
      // callbacks that would deadlock.)
      KJ_IF_MAYBE(finalSchema, content->finalSchema) {
        return module->getCompiler().getWorkspace().bootstrapLoader.loadOnce(*finalSchema);
      } else {
        return nullptr;
      }
604
    } else {
605
      return content->bootstrapSchema;
606
    }
Kenton Varda's avatar
Kenton Varda committed
607
  } else {
608 609 610 611
    return nullptr;
  }
}
kj::Maybe<schema::Node::Reader> Compiler::Node::getFinalSchema() {
Kenton Varda's avatar
Kenton Varda committed
612 613 614
  KJ_IF_MAYBE(schema, loadedFinalSchema) {
    return *schema;
  } else KJ_IF_MAYBE(content, getContent(Content::FINISHED)) {
615 616 617
    return content->finalSchema;
  } else {
    return nullptr;
Kenton Varda's avatar
Kenton Varda committed
618 619
  }
}
620 621 622 623 624 625 626
void Compiler::Node::loadFinalSchema(const SchemaLoader& loader) {
  KJ_IF_MAYBE(content, getContent(Content::FINISHED)) {
    KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&](){
      KJ_IF_MAYBE(finalSchema, content->finalSchema) {
        KJ_MAP(auxSchema, content->auxSchemas) {
          return loader.loadOnce(auxSchema);
        };
Kenton Varda's avatar
Kenton Varda committed
627
        loadedFinalSchema = loader.loadOnce(*finalSchema).getProto();
628 629
      }
    })) {
Kenton Varda's avatar
Kenton Varda committed
630 631
      // Schema validation threw an exception.

632 633 634 635 636 637 638 639 640 641
      // Don't try loading this again.
      content->finalSchema = nullptr;

      // Only bother to report validation failures if we think we haven't seen any errors.
      // Otherwise we assume that the errors caused the validation failure.
      if (!module->getErrorReporter().hadErrors()) {
        addError(kj::str("Internal compiler bug: Schema failed validation:\n", *exception));
      }
    }
  }
Kenton Varda's avatar
Kenton Varda committed
642 643
}

644 645
void Compiler::Node::traverse(uint eagerness, std::unordered_map<Node*, uint>& seen,
                              const SchemaLoader& finalLoader) {
646 647 648 649 650 651 652
  uint& slot = seen[this];
  if ((slot & eagerness) == eagerness) {
    // We've already covered this node.
    return;
  }
  slot |= eagerness;

653 654
  KJ_IF_MAYBE(content, getContent(Content::FINISHED)) {
    loadFinalSchema(finalLoader);
655

656 657 658 659 660 661 662 663 664 665
    KJ_IF_MAYBE(schema, getFinalSchema()) {
      if (eagerness / DEPENDENCIES != 0) {
        // For traversing dependencies, discard the bits lower than DEPENDENCIES and replace
        // them with the bits above DEPENDENCIES shifted over.
        uint newEagerness = (eagerness & ~(DEPENDENCIES - 1)) | (eagerness / DEPENDENCIES);

        traverseNodeDependencies(*schema, newEagerness, seen, finalLoader);
        for (auto& aux: content->auxSchemas) {
          traverseNodeDependencies(aux, newEagerness, seen, finalLoader);
        }
666 667 668 669 670 671
      }
    }
  }

  if (eagerness & PARENTS) {
    KJ_IF_MAYBE(p, parent) {
672
      p->traverse(eagerness, seen, finalLoader);
673 674 675 676
    }
  }

  if (eagerness & CHILDREN) {
677 678 679 680
    KJ_IF_MAYBE(content, getContent(Content::EXPANDED)) {
      for (auto& child: content->orderedNestedNodes) {
        child->traverse(eagerness, seen, finalLoader);
      }
681 682 683 684
    }
  }
}

Kenton Varda's avatar
Kenton Varda committed
685
void Compiler::Node::traverseNodeDependencies(
Kenton Varda's avatar
Kenton Varda committed
686
    const schema::Node::Reader& schemaNode, uint eagerness,
687 688
    std::unordered_map<Node*, uint>& seen,
    const SchemaLoader& finalLoader) {
Kenton Varda's avatar
Kenton Varda committed
689
  switch (schemaNode.which()) {
Kenton Varda's avatar
Kenton Varda committed
690
    case schema::Node::STRUCT:
Kenton Varda's avatar
Kenton Varda committed
691 692
      for (auto field: schemaNode.getStruct().getFields()) {
        switch (field.which()) {
693
          case schema::Field::SLOT:
694
            traverseType(field.getSlot().getType(), eagerness, seen, finalLoader);
Kenton Varda's avatar
Kenton Varda committed
695
            break;
Kenton Varda's avatar
Kenton Varda committed
696
          case schema::Field::GROUP:
Kenton Varda's avatar
Kenton Varda committed
697 698 699 700
            // Aux node will be scanned later.
            break;
        }

701
        traverseAnnotations(field.getAnnotations(), eagerness, seen, finalLoader);
Kenton Varda's avatar
Kenton Varda committed
702 703 704
      }
      break;

Kenton Varda's avatar
Kenton Varda committed
705
    case schema::Node::ENUM:
706
      for (auto enumerant: schemaNode.getEnum().getEnumerants()) {
707
        traverseAnnotations(enumerant.getAnnotations(), eagerness, seen, finalLoader);
Kenton Varda's avatar
Kenton Varda committed
708 709 710
      }
      break;

711 712
    case schema::Node::INTERFACE: {
      auto interface = schemaNode.getInterface();
713 714 715 716
      for (auto superclass: interface.getSuperclasses()) {
        uint64_t superclassId = superclass.getId();
        if (superclassId != 0) {  // if zero, we reported an error earlier
          traverseDependency(superclassId, eagerness, seen, finalLoader);
717
        }
718
        traverseBrand(superclass.getBrand(), eagerness, seen, finalLoader);
719 720
      }
      for (auto method: interface.getMethods()) {
721
        traverseDependency(method.getParamStructType(), eagerness, seen, finalLoader, true);
722
        traverseBrand(method.getParamBrand(), eagerness, seen, finalLoader);
723
        traverseDependency(method.getResultStructType(), eagerness, seen, finalLoader, true);
724
        traverseBrand(method.getResultBrand(), eagerness, seen, finalLoader);
725
        traverseAnnotations(method.getAnnotations(), eagerness, seen, finalLoader);
Kenton Varda's avatar
Kenton Varda committed
726 727
      }
      break;
728
    }
Kenton Varda's avatar
Kenton Varda committed
729

Kenton Varda's avatar
Kenton Varda committed
730 731 732 733 734 735 736 737
    case schema::Node::CONST:
      traverseType(schemaNode.getConst().getType(), eagerness, seen, finalLoader);
      break;

    case schema::Node::ANNOTATION:
      traverseType(schemaNode.getAnnotation().getType(), eagerness, seen, finalLoader);
      break;

Kenton Varda's avatar
Kenton Varda committed
738 739 740 741
    default:
      break;
  }

742
  traverseAnnotations(schemaNode.getAnnotations(), eagerness, seen, finalLoader);
Kenton Varda's avatar
Kenton Varda committed
743 744
}

Kenton Varda's avatar
Kenton Varda committed
745
void Compiler::Node::traverseType(const schema::Type::Reader& type, uint eagerness,
746 747
                                  std::unordered_map<Node*, uint>& seen,
                                  const SchemaLoader& finalLoader) {
748
  uint64_t id = 0;
749
  schema::Brand::Reader brand;
Kenton Varda's avatar
Kenton Varda committed
750
  switch (type.which()) {
Kenton Varda's avatar
Kenton Varda committed
751
    case schema::Type::STRUCT:
752
      id = type.getStruct().getTypeId();
753
      brand = type.getStruct().getBrand();
754
      break;
Kenton Varda's avatar
Kenton Varda committed
755
    case schema::Type::ENUM:
756
      id = type.getEnum().getTypeId();
757
      brand = type.getEnum().getBrand();
758
      break;
Kenton Varda's avatar
Kenton Varda committed
759
    case schema::Type::INTERFACE:
760
      id = type.getInterface().getTypeId();
761
      brand = type.getInterface().getBrand();
762
      break;
Kenton Varda's avatar
Kenton Varda committed
763
    case schema::Type::LIST:
764
      traverseType(type.getList().getElementType(), eagerness, seen, finalLoader);
765 766 767 768 769
      return;
    default:
      return;
  }

770
  traverseDependency(id, eagerness, seen, finalLoader);
771
  traverseBrand(brand, eagerness, seen, finalLoader);
Kenton Varda's avatar
Kenton Varda committed
772 773
}

774 775
void Compiler::Node::traverseBrand(
    const schema::Brand::Reader& brand, uint eagerness,
Kenton Varda's avatar
Kenton Varda committed
776 777
    std::unordered_map<Node*, uint>& seen,
    const SchemaLoader& finalLoader) {
778
  for (auto scope: brand.getScopes()) {
779
    switch (scope.which()) {
780
      case schema::Brand::Scope::BIND:
781 782
        for (auto binding: scope.getBind()) {
          switch (binding.which()) {
783
            case schema::Brand::Binding::UNBOUND:
784
              break;
785
            case schema::Brand::Binding::TYPE:
786 787 788 789 790
              traverseType(binding.getType(), eagerness, seen, finalLoader);
              break;
          }
        }
        break;
791
      case schema::Brand::Scope::INHERIT:
792
        break;
Kenton Varda's avatar
Kenton Varda committed
793 794
    }
  }
795 796 797
}

void Compiler::Node::traverseDependency(uint64_t depId, uint eagerness,
798 799 800
                                        std::unordered_map<Node*, uint>& seen,
                                        const SchemaLoader& finalLoader,
                                        bool ignoreIfNotFound) {
801
  KJ_IF_MAYBE(node, module->getCompiler().findNode(depId)) {
802
    node->traverse(eagerness, seen, finalLoader);
803
  } else if (!ignoreIfNotFound) {
804
    KJ_FAIL_ASSERT("Dependency ID not present in compiler?", depId);
805 806 807
  }
}

Kenton Varda's avatar
Kenton Varda committed
808
void Compiler::Node::traverseAnnotations(const List<schema::Annotation>::Reader& annotations,
809
                                         uint eagerness,
810 811
                                         std::unordered_map<Node*, uint>& seen,
                                         const SchemaLoader& finalLoader) {
812 813
  for (auto annotation: annotations) {
    KJ_IF_MAYBE(node, module->getCompiler().findNode(annotation.getId())) {
814
      node->traverse(eagerness, seen, finalLoader);
815 816 817 818 819
    }
  }
}


820
void Compiler::Node::addError(kj::StringPtr error) {
Kenton Varda's avatar
Kenton Varda committed
821 822 823
  module->getErrorReporter().addError(startByte, endByte, error);
}

824
kj::Maybe<NodeTranslator::Resolver::ResolveResult>
Kenton Varda's avatar
Kenton Varda committed
825 826 827
Compiler::Node::resolve(kj::StringPtr name) {
  // Check members.
  KJ_IF_MAYBE(member, resolveMember(name)) {
828
    return *member;
Kenton Varda's avatar
Kenton Varda committed
829 830 831 832 833 834 835
  }

  // Check parameters.
  // TODO(perf): Maintain a map?
  auto params = declaration.getParameters();
  for (uint i: kj::indices(params)) {
    if (params[i].getName() == name) {
836
      ResolveResult result;
Kenton Varda's avatar
Kenton Varda committed
837 838 839 840 841 842 843 844 845
      result.init<ResolvedParameter>(ResolvedParameter {id, i});
      return result;
    }
  }

  // Check parent scope.
  KJ_IF_MAYBE(p, parent) {
    return p->resolve(name);
  } else KJ_IF_MAYBE(b, module->getCompiler().lookupBuiltin(name)) {
846
    ResolveResult result;
847
    result.init<ResolvedDecl>(ResolvedDecl { b->id, b->genericParamCount, 0, b->kind, b, nullptr });
Kenton Varda's avatar
Kenton Varda committed
848 849 850 851 852 853
    return result;
  } else {
    return nullptr;
  }
}

854
kj::Maybe<NodeTranslator::Resolver::ResolveResult>
Kenton Varda's avatar
Kenton Varda committed
855 856 857 858 859 860 861 862
Compiler::Node::resolveMember(kj::StringPtr name) {
  if (isBuiltin) return nullptr;

  KJ_IF_MAYBE(content, getContent(Content::EXPANDED)) {
    {
      auto iter = content->nestedNodes.find(name);
      if (iter != content->nestedNodes.end()) {
        Node* node = iter->second;
863
        ResolveResult result;
Kenton Varda's avatar
Kenton Varda committed
864
        result.init<ResolvedDecl>(ResolvedDecl {
865
            node->id, node->genericParamCount, id, node->kind, node, nullptr });
Kenton Varda's avatar
Kenton Varda committed
866 867 868 869 870 871
        return result;
      }
    }
    {
      auto iter = content->aliases.find(name);
      if (iter != content->aliases.end()) {
872
        return iter->second->compile();
Kenton Varda's avatar
Kenton Varda committed
873 874 875 876 877 878
      }
    }
  }
  return nullptr;
}

879 880
NodeTranslator::Resolver::ResolvedDecl Compiler::Node::resolveBuiltin(Declaration::Which which) {
  auto& b = module->getCompiler().getBuiltin(which);
881
  return { b.id, b.genericParamCount, 0, b.kind, &b, nullptr };
882 883 884 885 886
}

NodeTranslator::Resolver::ResolvedDecl Compiler::Node::resolveId(uint64_t id) {
  auto& n = KJ_ASSERT_NONNULL(module->getCompiler().findNode(id));
  uint64_t parentId = n.parent.map([](Node& n) { return n.id; }).orDefault(0);
887
  return { n.id, n.genericParamCount, parentId, n.kind, &n, nullptr };
888 889
}

890 891 892
kj::Maybe<NodeTranslator::Resolver::ResolvedDecl> Compiler::Node::getParent() {
  return parent.map([](Node& parent) {
    uint64_t scopeId = parent.parent.map([](Node& gp) { return gp.id; }).orDefault(0);
893
    return ResolvedDecl { parent.id, parent.genericParamCount, scopeId, parent.kind, &parent, nullptr };
894 895 896
  });
}

Kenton Varda's avatar
Kenton Varda committed
897 898
NodeTranslator::Resolver::ResolvedDecl Compiler::Node::getTopScope() {
  Node& node = module->getRootNode();
899
  return ResolvedDecl { node.id, 0, 0, node.kind, &node, nullptr };
Kenton Varda's avatar
Kenton Varda committed
900 901
}

902
kj::Maybe<Schema> Compiler::Node::resolveBootstrapSchema(
903
    uint64_t id, schema::Brand::Reader brand) {
Kenton Varda's avatar
Kenton Varda committed
904
  KJ_IF_MAYBE(node, module->getCompiler().findNode(id)) {
905 906 907 908 909
    // Make sure the bootstrap schema is loaded into the SchemaLoader.
    if (node->getBootstrapSchema() == nullptr) {
      return nullptr;
    }

910 911
    // Now we actually invoke get() to evaluate the brand.
    return module->getCompiler().getWorkspace().bootstrapLoader.get(id, brand);
Kenton Varda's avatar
Kenton Varda committed
912 913 914
  } else {
    KJ_FAIL_REQUIRE("Tried to get schema for ID we haven't seen before.");
  }
Kenton Varda's avatar
Kenton Varda committed
915 916
}

917
kj::Maybe<schema::Node::Reader> Compiler::Node::resolveFinalSchema(uint64_t id) {
Kenton Varda's avatar
Kenton Varda committed
918 919 920 921 922
  KJ_IF_MAYBE(node, module->getCompiler().findNode(id)) {
    return node->getFinalSchema();
  } else {
    KJ_FAIL_REQUIRE("Tried to get schema for ID we haven't seen before.");
  }
Kenton Varda's avatar
Kenton Varda committed
923 924
}

Kenton Varda's avatar
Kenton Varda committed
925 926
kj::Maybe<NodeTranslator::Resolver::ResolvedDecl>
Compiler::Node::resolveImport(kj::StringPtr name) {
927
  KJ_IF_MAYBE(m, module->importRelative(name)) {
Kenton Varda's avatar
Kenton Varda committed
928
    Node& root = m->getRootNode();
929
    return ResolvedDecl { root.id, 0, 0, root.kind, &root, nullptr };
930 931 932 933 934
  } else {
    return nullptr;
  }
}

935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950
kj::Maybe<Type> Compiler::Node::resolveBootstrapType(schema::Type::Reader type, Schema scope) {
  // TODO(someday): Arguably should return null if the type or its dependencies are placeholders.

  kj::Maybe<Type> result;
  KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]() {
    result = module->getCompiler().getWorkspace().bootstrapLoader.getType(type, scope);
  })) {
    result = nullptr;
    if (!module->getErrorReporter().hadErrors()) {
      addError(kj::str("Internal compiler bug: Bootstrap schema failed to load:\n",
                       *exception));
    }
  }
  return result;
}

Kenton Varda's avatar
Kenton Varda committed
951 952
// =======================================================================================

953
Compiler::CompiledModule::CompiledModule(Compiler::Impl& compiler, Module& parserModule)
Kenton Varda's avatar
Kenton Varda committed
954 955 956 957
    : compiler(compiler), parserModule(parserModule),
      content(parserModule.loadContent(contentArena.getOrphanage())),
      rootNode(*this) {}

958 959
kj::Maybe<Compiler::CompiledModule&> Compiler::CompiledModule::importRelative(
    kj::StringPtr importPath) {
Kenton Varda's avatar
Kenton Varda committed
960
  return parserModule.importRelative(importPath).map(
961
      [this](Module& module) -> Compiler::CompiledModule& {
962
        return compiler.addInternal(module);
Kenton Varda's avatar
Kenton Varda committed
963 964 965
      });
}

Kenton Varda's avatar
Kenton Varda committed
966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986
static void findImports(Expression::Reader exp, std::set<kj::StringPtr>& output) {
  switch (exp.which()) {
    case Expression::UNKNOWN:
    case Expression::POSITIVE_INT:
    case Expression::NEGATIVE_INT:
    case Expression::FLOAT:
    case Expression::STRING:
    case Expression::BINARY:
    case Expression::RELATIVE_NAME:
    case Expression::ABSOLUTE_NAME:
      break;

    case Expression::IMPORT:
      output.insert(exp.getImport().getValue());
      break;

    case Expression::LIST:
      for (auto element: exp.getList()) {
        findImports(element, output);
      }
      break;
Kenton Varda's avatar
Kenton Varda committed
987

Kenton Varda's avatar
Kenton Varda committed
988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006
    case Expression::TUPLE:
      for (auto element: exp.getTuple()) {
        findImports(element.getValue(), output);
      }
      break;

    case Expression::APPLICATION: {
      auto app = exp.getApplication();
      findImports(app.getFunction(), output);
      for (auto param: app.getParams()) {
        findImports(param.getValue(), output);
      }
      break;
    }

    case Expression::MEMBER: {
      findImports(exp.getMember().getParent(), output);
      break;
    }
Kenton Varda's avatar
Kenton Varda committed
1007 1008 1009 1010
  }
}

static void findImports(Declaration::Reader decl, std::set<kj::StringPtr>& output) {
1011 1012 1013
  switch (decl.which()) {
    case Declaration::USING:
      findImports(decl.getUsing().getTarget(), output);
Kenton Varda's avatar
Kenton Varda committed
1014
      break;
1015 1016
    case Declaration::CONST:
      findImports(decl.getConst().getType(), output);
Kenton Varda's avatar
Kenton Varda committed
1017
      break;
1018 1019
    case Declaration::FIELD:
      findImports(decl.getField().getType(), output);
Kenton Varda's avatar
Kenton Varda committed
1020
      break;
1021
    case Declaration::INTERFACE:
1022 1023
      for (auto superclass: decl.getInterface().getSuperclasses()) {
        findImports(superclass, output);
1024 1025
      }
      break;
1026 1027
    case Declaration::METHOD: {
      auto method = decl.getMethod();
1028 1029 1030 1031 1032 1033 1034 1035

      auto params = method.getParams();
      if (params.isNamedList()) {
        for (auto param: params.getNamedList()) {
          findImports(param.getType(), output);
          for (auto ann: param.getAnnotations()) {
            findImports(ann.getName(), output);
          }
Kenton Varda's avatar
Kenton Varda committed
1036
        }
1037 1038
      } else {
        findImports(params.getType(), output);
Kenton Varda's avatar
Kenton Varda committed
1039
      }
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052

      if (method.getResults().isExplicit()) {
        auto results = method.getResults().getExplicit();
        if (results.isNamedList()) {
          for (auto param: results.getNamedList()) {
            findImports(param.getType(), output);
            for (auto ann: param.getAnnotations()) {
              findImports(ann.getName(), output);
            }
          }
        } else {
          findImports(results.getType(), output);
        }
Kenton Varda's avatar
Kenton Varda committed
1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
      }
      break;
    }
    default:
      break;
  }

  for (auto ann: decl.getAnnotations()) {
    findImports(ann.getName(), output);
  }

  for (auto nested: decl.getNestedDecls()) {
    findImports(nested, output);
  }
}

Kenton Varda's avatar
Kenton Varda committed
1069
Orphan<List<schema::CodeGeneratorRequest::RequestedFile::Import>>
1070
    Compiler::CompiledModule::getFileImportTable(Orphanage orphanage) {
Kenton Varda's avatar
Kenton Varda committed
1071 1072 1073
  std::set<kj::StringPtr> importNames;
  findImports(content.getReader().getRoot(), importNames);

Kenton Varda's avatar
Kenton Varda committed
1074
  auto result = orphanage.newOrphan<List<schema::CodeGeneratorRequest::RequestedFile::Import>>(
Kenton Varda's avatar
Kenton Varda committed
1075 1076 1077 1078 1079 1080
      importNames.size());
  auto builder = result.get();

  uint i = 0;
  for (auto name: importNames) {
    // We presumably ran this import before, so it shouldn't throw now.
1081
    auto entry = builder[i++];
Kenton Varda's avatar
Kenton Varda committed
1082 1083 1084 1085 1086 1087 1088
    entry.setId(KJ_ASSERT_NONNULL(importRelative(name)).rootNode.getId());
    entry.setName(name);
  }

  return result;
}

Kenton Varda's avatar
Kenton Varda committed
1089 1090
// =======================================================================================

1091
Compiler::Impl::Impl(AnnotationFlag annotationFlag)
1092
    : annotationFlag(annotationFlag), workspace(*this) {
Kenton Varda's avatar
Kenton Varda committed
1093 1094
  // Reflectively interpret the members of Declaration.body.  Any member prefixed by "builtin"
  // defines a builtin declaration visible in the global scope.
1095

1096 1097 1098
  StructSchema declSchema = Schema::from<Declaration>();
  for (auto field: declSchema.getFields()) {
    auto fieldProto = field.getProto();
1099
    if (fieldProto.getDiscriminantValue() != schema::Field::NO_DISCRIMINANT) {
1100 1101 1102
      auto name = fieldProto.getName();
      if (name.startsWith("builtin")) {
        kj::StringPtr symbolName = name.slice(strlen("builtin"));
Kenton Varda's avatar
Kenton Varda committed
1103

1104
        List<Declaration::BrandParameter>::Reader params;
Kenton Varda's avatar
Kenton Varda committed
1105 1106
        for (auto annotation: fieldProto.getAnnotations()) {
          if (annotation.getId() == 0x94099c3f9eb32d6bull) {
1107
            params = annotation.getValue().getList().getAs<List<Declaration::BrandParameter>>();
Kenton Varda's avatar
Kenton Varda committed
1108 1109 1110 1111
            break;
          }
        }

1112 1113 1114 1115 1116
        Declaration::Which which =
            static_cast<Declaration::Which>(fieldProto.getDiscriminantValue());
        kj::Own<Node> newNode = nodeArena.allocateOwn<Node>(symbolName, which, params);
        builtinDeclsByKind[which] = newNode;
        builtinDecls[symbolName] = kj::mv(newNode);
1117
      }
Kenton Varda's avatar
Kenton Varda committed
1118 1119 1120 1121
    }
  }
}

1122
Compiler::Impl::~Impl() noexcept(false) {}
1123

1124 1125
void Compiler::Impl::clearWorkspace() {
  // Make sure we reconstruct the workspace even if destroying it throws an exception.
1126 1127
  KJ_DEFER(kj::ctor(workspace, *this));
  kj::dtor(workspace);
1128 1129
}

1130 1131
Compiler::CompiledModule& Compiler::Impl::addInternal(Module& parsedModule) {
  kj::Own<CompiledModule>& slot = modules[&parsedModule];
1132 1133 1134 1135 1136 1137 1138
  if (slot.get() == nullptr) {
    slot = kj::heap<CompiledModule>(*this, parsedModule);
  }

  return *slot;
}

1139
uint64_t Compiler::Impl::addNode(uint64_t desiredId, Node& node) {
Kenton Varda's avatar
Kenton Varda committed
1140
  for (;;) {
1141
    auto insertResult = nodesById.insert(std::make_pair(desiredId, &node));
Kenton Varda's avatar
Kenton Varda committed
1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155
    if (insertResult.second) {
      return desiredId;
    }

    // Only report an error if this ID is not bogus.  Actual IDs specified in the original source
    // code are required to have the upper bit set.  Anything else must have been manufactured
    // at some point to cover up an error.
    if (desiredId & (1ull << 63)) {
      node.addError(kj::str("Duplicate ID @0x", kj::hex(desiredId), "."));
      insertResult.first->second->addError(
          kj::str("ID @0x", kj::hex(desiredId), " originally used here."));
    }

    // Assign a new bogus ID.
1156
    desiredId = nextBogusId++;
Kenton Varda's avatar
Kenton Varda committed
1157 1158 1159
  }
}

1160 1161 1162
kj::Maybe<Compiler::Node&> Compiler::Impl::findNode(uint64_t id) {
  auto iter = nodesById.find(id);
  if (iter == nodesById.end()) {
Kenton Varda's avatar
Kenton Varda committed
1163 1164 1165 1166 1167 1168
    return nullptr;
  } else {
    return *iter->second;
  }
}

1169
kj::Maybe<Compiler::Node&> Compiler::Impl::lookupBuiltin(kj::StringPtr name) {
Kenton Varda's avatar
Kenton Varda committed
1170 1171 1172 1173 1174 1175 1176 1177
  auto iter = builtinDecls.find(name);
  if (iter == builtinDecls.end()) {
    return nullptr;
  } else {
    return *iter->second;
  }
}

1178 1179 1180 1181 1182 1183
Compiler::Node& Compiler::Impl::getBuiltin(Declaration::Which which) {
  auto iter = builtinDeclsByKind.find(which);
  KJ_REQUIRE(iter != builtinDeclsByKind.end(), "invalid builtin", (uint)which);
  return *iter->second;
}

1184
uint64_t Compiler::Impl::add(Module& module) {
1185
  return addInternal(module).getRootNode().getId();
1186 1187
}

1188
kj::Maybe<uint64_t> Compiler::Impl::lookup(uint64_t parent, kj::StringPtr childName) {
1189
  // Looking up members does not use the workspace, so we don't need to lock it.
1190
  KJ_IF_MAYBE(parentNode, findNode(parent)) {
Kenton Varda's avatar
Kenton Varda committed
1191 1192 1193 1194 1195 1196 1197
    KJ_IF_MAYBE(child, parentNode->resolveMember(childName)) {
      if (child->is<NodeTranslator::Resolver::ResolvedDecl>()) {
        return child->get<NodeTranslator::Resolver::ResolvedDecl>().id;
      } else {
        // An alias. We don't support looking up aliases with this method.
        return nullptr;
      }
1198 1199 1200
    } else {
      return nullptr;
    }
1201 1202 1203 1204 1205
  } else {
    KJ_FAIL_REQUIRE("lookup()s parameter 'parent' must be a known ID.", parent);
  }
}

Kenton Varda's avatar
Kenton Varda committed
1206
Orphan<List<schema::CodeGeneratorRequest::RequestedFile::Import>>
1207
    Compiler::Impl::getFileImportTable(Module& module, Orphanage orphanage) {
Kenton Varda's avatar
Kenton Varda committed
1208 1209 1210
  return addInternal(module).getFileImportTable(orphanage);
}

1211 1212
void Compiler::Impl::eagerlyCompile(uint64_t id, uint eagerness,
                                    const SchemaLoader& finalLoader) {
1213
  KJ_IF_MAYBE(node, findNode(id)) {
1214 1215
    std::unordered_map<Node*, uint> seen;
    node->traverse(eagerness, seen, finalLoader);
1216 1217 1218 1219 1220
  } else {
    KJ_FAIL_REQUIRE("id did not come from this Compiler.", id);
  }
}

Kenton Varda's avatar
Kenton Varda committed
1221
void Compiler::Impl::load(const SchemaLoader& loader, uint64_t id) const {
1222 1223 1224 1225 1226 1227 1228 1229 1230 1231
  // We know that this load() is only called from the bootstrap loader which is already protected
  // by our mutex, so we can drop thread-safety.
  auto& self = const_cast<Compiler::Impl&>(*this);

  KJ_IF_MAYBE(node, self.findNode(id)) {
    node->getBootstrapSchema();
  }
}

void Compiler::Impl::loadFinal(const SchemaLoader& loader, uint64_t id) {
Kenton Varda's avatar
Kenton Varda committed
1232
  KJ_IF_MAYBE(node, findNode(id)) {
1233
    node->loadFinalSchema(loader);
Kenton Varda's avatar
Kenton Varda committed
1234 1235 1236
  }
}

1237 1238
// =======================================================================================

1239 1240 1241
Compiler::Compiler(AnnotationFlag annotationFlag)
    : impl(kj::heap<Impl>(annotationFlag)),
      loader(*this) {}
1242
Compiler::~Compiler() noexcept(false) {}
1243

1244 1245
uint64_t Compiler::add(Module& module) const {
  return impl.lockExclusive()->get()->add(module);
1246 1247
}

1248
kj::Maybe<uint64_t> Compiler::lookup(uint64_t parent, kj::StringPtr childName) const {
1249
  return impl.lockExclusive()->get()->lookup(parent, childName);
1250 1251
}

Kenton Varda's avatar
Kenton Varda committed
1252
Orphan<List<schema::CodeGeneratorRequest::RequestedFile::Import>>
1253 1254
    Compiler::getFileImportTable(Module& module, Orphanage orphanage) const {
  return impl.lockExclusive()->get()->getFileImportTable(module, orphanage);
Kenton Varda's avatar
Kenton Varda committed
1255 1256
}

1257
void Compiler::eagerlyCompile(uint64_t id, uint eagerness) const {
1258
  impl.lockExclusive()->get()->eagerlyCompile(id, eagerness, loader);
1259 1260
}

1261 1262
void Compiler::clearWorkspace() const {
  impl.lockExclusive()->get()->clearWorkspace();
1263 1264
}

1265 1266
void Compiler::load(const SchemaLoader& loader, uint64_t id) const {
  impl.lockExclusive()->get()->loadFinal(loader, id);
1267 1268
}

Kenton Varda's avatar
Kenton Varda committed
1269 1270
}  // namespace compiler
}  // namespace capnp