Commit b92a28a6 authored by Kenton Varda's avatar Kenton Varda

Compiler nearing completion. Mostly just needs a driver.

parent 34e70d5a
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "lexer.h" #include "lexer.h"
#include "parser.h" #include "parser.h"
#include "compiler.h"
#include <capnp/pretty-print.h> #include <capnp/pretty-print.h>
#include <kj/vector.h> #include <kj/vector.h>
#include <kj/io.h> #include <kj/io.h>
...@@ -31,8 +32,22 @@ ...@@ -31,8 +32,22 @@
#include "../message.h" #include "../message.h"
#include <iostream> #include <iostream>
class CerrErrorReporter: public capnp::compiler::ErrorReporter { class DummyModule: public capnp::compiler::Module {
public: public:
capnp::compiler::ParsedFile::Reader content;
kj::StringPtr getLocalName() const {
return "(stdin)";
}
kj::StringPtr getSourceName() const {
return "(stdin)";
}
capnp::Orphan<capnp::compiler::ParsedFile> loadContent(capnp::Orphanage orphanage) const {
return orphanage.newOrphanCopy(content);
}
kj::Maybe<const Module&> importRelative(kj::StringPtr importPath) const {
return nullptr;
}
void addError(uint32_t startByte, uint32_t endByte, kj::StringPtr message) const override { void addError(uint32_t startByte, uint32_t endByte, kj::StringPtr message) const override {
std::cerr << "input:" << startByte << "-" << endByte << ": " << message.cStr() << std::endl; std::cerr << "input:" << startByte << "-" << endByte << ": " << message.cStr() << std::endl;
} }
...@@ -41,18 +56,23 @@ public: ...@@ -41,18 +56,23 @@ public:
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
// Eventually this will be capnpc. For now it's just a dummy program that tests parsing. // Eventually this will be capnpc. For now it's just a dummy program that tests parsing.
kj::Vector<char> input; // kj::Vector<char> input;
char buffer[4096]; // char buffer[4096];
for (;;) { // for (;;) {
ssize_t n; // ssize_t n;
KJ_SYSCALL(n = read(STDIN_FILENO, buffer, sizeof(buffer))); // KJ_SYSCALL(n = read(STDIN_FILENO, buffer, sizeof(buffer)));
if (n == 0) { // if (n == 0) {
break; // break;
} // }
input.addAll(buffer, buffer + n); // input.addAll(buffer, buffer + n);
} // }
kj::StringPtr input =
"@0x8e001c75f6ff54c8;\n"
"struct Foo { bar @0 :Int32 = 123; baz @1 :Text; }\n"
"struct Qux { foo @0 :List(Int32) = [12, 34]; }";
CerrErrorReporter errorReporter; DummyModule module;
std::cout << "=========================================================================\n" std::cout << "=========================================================================\n"
<< "lex\n" << "lex\n"
...@@ -61,7 +81,7 @@ int main(int argc, char* argv[]) { ...@@ -61,7 +81,7 @@ int main(int argc, char* argv[]) {
capnp::MallocMessageBuilder lexerArena; capnp::MallocMessageBuilder lexerArena;
auto lexedFile = lexerArena.initRoot<capnp::compiler::LexedStatements>(); auto lexedFile = lexerArena.initRoot<capnp::compiler::LexedStatements>();
capnp::compiler::lex(input, lexedFile, errorReporter); capnp::compiler::lex(input, lexedFile, module);
std::cout << capnp::prettyPrint(lexedFile).cStr() << std::endl; std::cout << capnp::prettyPrint(lexedFile).cStr() << std::endl;
std::cout << "=========================================================================\n" std::cout << "=========================================================================\n"
...@@ -71,8 +91,21 @@ int main(int argc, char* argv[]) { ...@@ -71,8 +91,21 @@ int main(int argc, char* argv[]) {
capnp::MallocMessageBuilder parserArena; capnp::MallocMessageBuilder parserArena;
auto parsedFile = parserArena.initRoot<capnp::compiler::ParsedFile>(); auto parsedFile = parserArena.initRoot<capnp::compiler::ParsedFile>();
capnp::compiler::parseFile(lexedFile.getStatements(), parsedFile, errorReporter); capnp::compiler::parseFile(lexedFile.getStatements(), parsedFile, module);
std::cout << capnp::prettyPrint(parsedFile).cStr() << std::endl; std::cout << capnp::prettyPrint(parsedFile).cStr() << std::endl;
std::cout << "=========================================================================\n"
<< "compile\n"
<< "========================================================================="
<< std::endl;
module.content = parsedFile.asReader();
capnp::compiler::Compiler compiler;
compiler.add(module, capnp::compiler::Compiler::EAGER);
for (auto schema: compiler.getLoader().getAllLoaded()) {
std::cout << capnp::prettyPrint(schema.getProto()).cStr() << std::endl;
}
return 0; return 0;
} }
...@@ -68,8 +68,8 @@ public: ...@@ -68,8 +68,8 @@ public:
Node(kj::StringPtr name, Declaration::Body::Which kind); Node(kj::StringPtr name, Declaration::Body::Which kind);
// Create a dummy node representing a built-in declaration, like "Int32" or "true". // Create a dummy node representing a built-in declaration, like "Int32" or "true".
uint64_t getId() { return id; } uint64_t getId() const { return id; }
Declaration::Body::Which getKind() { return kind; } Declaration::Body::Which getKind() const { return kind; }
kj::Maybe<const Node&> lookupMember(kj::StringPtr name) const; kj::Maybe<const Node&> lookupMember(kj::StringPtr name) const;
// Find a direct member of this node with the given name. // Find a direct member of this node with the given name.
...@@ -81,16 +81,20 @@ public: ...@@ -81,16 +81,20 @@ public:
kj::Maybe<const Node&> lookup(const DeclName::Reader& name) const; kj::Maybe<const Node&> lookup(const DeclName::Reader& name) const;
// Resolve an arbitrary DeclName to a Node. // Resolve an arbitrary DeclName to a Node.
Schema getBootstrapOrFinalSchema() const; kj::Maybe<Schema> getBootstrapOrFinalSchema() const;
Schema getFinalSchema() const; kj::Maybe<Schema> getFinalSchema() const;
void traverse(Compiler::Mode mode) const;
// 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.
void addError(kj::StringPtr error) const; void addError(kj::StringPtr error) const;
// Report an error on this Node. // Report an error on this Node.
// implements NodeTranslator::Resolver ----------------------------- // implements NodeTranslator::Resolver -----------------------------
kj::Maybe<ResolvedName> resolve(const DeclName::Reader& name) const override; kj::Maybe<ResolvedName> resolve(const DeclName::Reader& name) const override;
Schema resolveMaybeBootstrapSchema(uint64_t id) const override; kj::Maybe<Schema> resolveMaybeBootstrapSchema(uint64_t id) const override;
Schema resolveFinalSchema(uint64_t id) const override; kj::Maybe<Schema> resolveFinalSchema(uint64_t id) const override;
private: private:
const CompiledModule* module; // null iff isBuiltin is true const CompiledModule* module; // null iff isBuiltin is true
...@@ -153,13 +157,14 @@ private: ...@@ -153,13 +157,14 @@ private:
NodeTranslator* translator; NodeTranslator* translator;
// Node translator, allocated in the bootstrap arena. // Node translator, allocated in the bootstrap arena.
Schema bootstrapSchema; kj::Maybe<Schema> bootstrapSchema;
// The schema built in the bootstrap loader. // The schema built in the bootstrap loader. Null if the bootstrap loader threw an exception.
// FINISHED ------------------------------------ // FINISHED ------------------------------------
Schema finalSchema; kj::Maybe<Schema> finalSchema;
// The complete schema as loaded by the compiler's main SchemaLoader. // The complete schema as loaded by the compiler's main SchemaLoader. Null if the final
// loader threw an exception.
}; };
kj::MutexGuarded<Content> content; kj::MutexGuarded<Content> content;
...@@ -188,7 +193,7 @@ public: ...@@ -188,7 +193,7 @@ public:
const Compiler::Impl& getCompiler() const { return compiler; } const Compiler::Impl& getCompiler() const { return compiler; }
const ErrorReporter& getErrorReporter() const { return parserModule; } const ErrorReporter& getErrorReporter() const { return parserModule; }
const ParsedFile::Reader& getParsedFile() const { return content; } ParsedFile::Reader getParsedFile() const { return content.getReader(); }
const Node& getRootNode() const { return rootNode; } const Node& getRootNode() const { return rootNode; }
kj::StringPtr getSourceName() const { return parserModule.getSourceName(); } kj::StringPtr getSourceName() const { return parserModule.getSourceName(); }
...@@ -198,14 +203,16 @@ private: ...@@ -198,14 +203,16 @@ private:
const Compiler::Impl& compiler; const Compiler::Impl& compiler;
const Module& parserModule; const Module& parserModule;
MallocMessageBuilder contentArena; MallocMessageBuilder contentArena;
ParsedFile::Reader content; Orphan<ParsedFile> content;
Node rootNode; Node rootNode;
}; };
class Compiler::Impl: public SchemaLoader::LazyLoadCallback { class Compiler::Impl: public SchemaLoader::LazyLoadCallback {
public: public:
Impl(); Impl();
virtual ~Impl();
uint64_t add(Module& module, Mode mode) const;
const CompiledModule& add(const Module& parsedModule) const; const CompiledModule& add(const Module& parsedModule) const;
struct Workspace { struct Workspace {
...@@ -214,18 +221,23 @@ public: ...@@ -214,18 +221,23 @@ public:
// compiler. Note that since nodes are compiled lazily, a new Workspace may have to be // compiler. Note that since nodes are compiled lazily, a new Workspace may have to be
// constructed in order to compile more nodes later. // constructed in order to compile more nodes later.
kj::Arena arena; MallocMessageBuilder message;
// Arena for allocating temporary native objects.
Orphanage orphanage; Orphanage orphanage;
// Orphanage for allocating temporary Cap'n Proto objects. // Orphanage for allocating temporary Cap'n Proto objects.
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`.
SchemaLoader bootstrapLoader; SchemaLoader bootstrapLoader;
// Loader used to load bootstrap schemas. The bootstrap schema nodes are similar to the final // 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. // 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). // 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 // These bootstrap schemas can then be plugged into the dynamic API and used to evaluate these
// remaining values. // remaining values.
inline Workspace(): orphanage(message.getOrphanage()) {}
}; };
const kj::Arena& getNodeArena() const { return nodeArena; } const kj::Arena& getNodeArena() const { return nodeArena; }
...@@ -261,10 +273,7 @@ private: ...@@ -261,10 +273,7 @@ private:
// the pointer to point at said stack workspace. The rest of the compiler can assume that this // the pointer to point at said stack workspace. The rest of the compiler can assume that this
// Workspace is active. // Workspace is active.
uint workspaceRefcount = 0; typedef std::unordered_map<const Module*, kj::Own<CompiledModule>> ModuleMap;
// Count of threads that have entered the compiler.
typedef std::unordered_map<Module*, kj::Own<CompiledModule>> ModuleMap;
kj::MutexGuarded<ModuleMap> modules; kj::MutexGuarded<ModuleMap> modules;
// Map of parser modules to compiler modules. // Map of parser modules to compiler modules.
...@@ -377,7 +386,7 @@ kj::StringPtr Compiler::Node::joinDisplayName( ...@@ -377,7 +386,7 @@ kj::StringPtr Compiler::Node::joinDisplayName(
result[separatorPos] = parent.parent == nullptr ? ':' : '.'; result[separatorPos] = parent.parent == nullptr ? ':' : '.';
memcpy(result.begin() + separatorPos + 1, declName.begin(), declName.size()); memcpy(result.begin() + separatorPos + 1, declName.begin(), declName.size());
result[result.size() - 1] = '\0'; result[result.size() - 1] = '\0';
return kj::StringPtr(declName.begin(), declName.size() - 1); return kj::StringPtr(result.begin(), result.size() - 1);
} }
const Compiler::Node::Content& Compiler::Node::getContent(Content::State minimumState) const { const Compiler::Node::Content& Compiler::Node::getContent(Content::State minimumState) const {
...@@ -459,8 +468,14 @@ const Compiler::Node::Content& Compiler::Node::getContent(Content::State minimum ...@@ -459,8 +468,14 @@ const Compiler::Node::Content& Compiler::Node::getContent(Content::State minimum
locked->translator = &workspace.arena.allocate<NodeTranslator>( locked->translator = &workspace.arena.allocate<NodeTranslator>(
*this, module->getErrorReporter(), declaration, kj::mv(schemaNode)); *this, module->getErrorReporter(), declaration, kj::mv(schemaNode));
KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&](){
locked->bootstrapSchema = workspace.bootstrapLoader.loadOnce( locked->bootstrapSchema = workspace.bootstrapLoader.loadOnce(
locked->translator->getBootstrapNode()); locked->translator->getBootstrapNode());
})) {
locked->bootstrapSchema = nullptr;
addError(kj::str("Internal compiler bug: Bootstrap schema failed validation: ",
exception->getDescription()));
}
// If the Workspace is destroyed while this Node is still in the BOOTSTRAP state, // If the Workspace is destroyed while this Node is still in the BOOTSTRAP state,
// revert it to the EXPANDED state, because the NodeTranslator is no longer valid in this // revert it to the EXPANDED state, because the NodeTranslator is no longer valid in this
...@@ -480,8 +495,14 @@ const Compiler::Node::Content& Compiler::Node::getContent(Content::State minimum ...@@ -480,8 +495,14 @@ const Compiler::Node::Content& Compiler::Node::getContent(Content::State minimum
if (minimumState <= Content::BOOTSTRAP) break; if (minimumState <= Content::BOOTSTRAP) break;
// Create the final schema. // Create the final schema.
KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&](){
locked->finalSchema = module->getCompiler().getFinalLoader().loadOnce( locked->finalSchema = module->getCompiler().getFinalLoader().loadOnce(
locked->translator->finish()); locked->translator->finish());
})) {
locked->finalSchema = nullptr;
addError(kj::str("Internal compiler bug: Schema failed validation: ",
exception->getDescription()));
}
locked->advanceState(Content::FINISHED); locked->advanceState(Content::FINISHED);
// no break // no break
...@@ -584,19 +605,30 @@ kj::Maybe<const Compiler::Node&> Compiler::Node::lookup(const DeclName::Reader& ...@@ -584,19 +605,30 @@ kj::Maybe<const Compiler::Node&> Compiler::Node::lookup(const DeclName::Reader&
return *node; return *node;
} }
Schema Compiler::Node::getBootstrapOrFinalSchema() const { kj::Maybe<Schema> Compiler::Node::getBootstrapOrFinalSchema() const {
auto& content = getContent(Content::BOOTSTRAP); auto& content = getContent(Content::BOOTSTRAP);
if (__atomic_load_n(&content.state, __ATOMIC_ACQUIRE) == Content::FINISHED) { if (__atomic_load_n(&content.state, __ATOMIC_ACQUIRE) == Content::FINISHED &&
content.finalSchema != nullptr) {
return content.finalSchema; return content.finalSchema;
} else { } else {
return content.bootstrapSchema; return content.bootstrapSchema;
} }
} }
Schema Compiler::Node::getFinalSchema() const { kj::Maybe<Schema> Compiler::Node::getFinalSchema() const {
return getContent(Content::FINISHED).finalSchema; return getContent(Content::FINISHED).finalSchema;
} }
void Compiler::Node::traverse(Compiler::Mode mode) const {
getFinalSchema();
if (mode == EAGER) {
for (auto& child: getContent(Content::EXPANDED).nestedNodes) {
child.second->traverse(mode);
}
}
}
void Compiler::Node::addError(kj::StringPtr error) const { void Compiler::Node::addError(kj::StringPtr error) const {
module->getErrorReporter().addError(startByte, endByte, error); module->getErrorReporter().addError(startByte, endByte, error);
} }
...@@ -608,7 +640,7 @@ kj::Maybe<NodeTranslator::Resolver::ResolvedName> Compiler::Node::resolve( ...@@ -608,7 +640,7 @@ kj::Maybe<NodeTranslator::Resolver::ResolvedName> Compiler::Node::resolve(
}); });
} }
Schema Compiler::Node::resolveMaybeBootstrapSchema(uint64_t id) const { kj::Maybe<Schema> Compiler::Node::resolveMaybeBootstrapSchema(uint64_t id) const {
KJ_IF_MAYBE(node, module->getCompiler().findNode(id)) { KJ_IF_MAYBE(node, module->getCompiler().findNode(id)) {
return node->getBootstrapOrFinalSchema(); return node->getBootstrapOrFinalSchema();
} else { } else {
...@@ -616,7 +648,7 @@ Schema Compiler::Node::resolveMaybeBootstrapSchema(uint64_t id) const { ...@@ -616,7 +648,7 @@ Schema Compiler::Node::resolveMaybeBootstrapSchema(uint64_t id) const {
} }
} }
Schema Compiler::Node::resolveFinalSchema(uint64_t id) const { kj::Maybe<Schema> Compiler::Node::resolveFinalSchema(uint64_t id) const {
KJ_IF_MAYBE(node, module->getCompiler().findNode(id)) { KJ_IF_MAYBE(node, module->getCompiler().findNode(id)) {
return node->getFinalSchema(); return node->getFinalSchema();
} else { } else {
...@@ -657,6 +689,19 @@ Compiler::Impl::Impl(): finalLoader(*this), workspace(nullptr) { ...@@ -657,6 +689,19 @@ Compiler::Impl::Impl(): finalLoader(*this), workspace(nullptr) {
} }
} }
Compiler::Impl::~Impl() {}
const Compiler::CompiledModule& Compiler::Impl::add(const Module& parsedModule) const {
auto locked = modules.lockExclusive();
kj::Own<CompiledModule>& slot = (*locked)[&parsedModule];
if (slot.get() == nullptr) {
slot = kj::heap<CompiledModule>(*this, parsedModule);
}
return *slot;
}
uint64_t Compiler::Impl::addNode(uint64_t desiredId, Node& node) const { uint64_t Compiler::Impl::addNode(uint64_t desiredId, Node& node) const {
auto lock = nodesById.lockExclusive(); auto lock = nodesById.lockExclusive();
for (;;) { for (;;) {
...@@ -698,6 +743,19 @@ kj::Maybe<const Compiler::Node&> Compiler::Impl::lookupBuiltin(kj::StringPtr nam ...@@ -698,6 +743,19 @@ kj::Maybe<const Compiler::Node&> Compiler::Impl::lookupBuiltin(kj::StringPtr nam
} }
} }
uint64_t Compiler::Impl::add(Module& module, Mode mode) const {
Impl::Workspace workspace;
auto lock = this->workspace.lockExclusive();
*lock = &workspace;
KJ_DEFER(*lock = nullptr);
auto& node = add(module).getRootNode();
if (mode != LAZY) {
node.traverse(mode);
}
return node.getId();
}
void Compiler::Impl::load(const SchemaLoader& loader, uint64_t id) const { void Compiler::Impl::load(const SchemaLoader& loader, uint64_t id) const {
KJ_IF_MAYBE(node, findNode(id)) { KJ_IF_MAYBE(node, findNode(id)) {
if (&loader == &finalLoader) { if (&loader == &finalLoader) {
...@@ -713,5 +771,18 @@ void Compiler::Impl::load(const SchemaLoader& loader, uint64_t id) const { ...@@ -713,5 +771,18 @@ void Compiler::Impl::load(const SchemaLoader& loader, uint64_t id) const {
} }
} }
// =======================================================================================
Compiler::Compiler(): impl(kj::heap<Impl>()) {}
Compiler::~Compiler() {}
uint64_t Compiler::add(Module& module, Mode mode) const {
return impl->add(module, mode);
}
const SchemaLoader& Compiler::getLoader() const {
return impl->getFinalLoader();
}
} // namespace compiler } // namespace compiler
} // namespace capnp } // namespace capnp
...@@ -55,7 +55,7 @@ class Compiler { ...@@ -55,7 +55,7 @@ class Compiler {
// Cross-links separate modules (schema files) and translates them into schema nodes. // Cross-links separate modules (schema files) and translates them into schema nodes.
public: public:
explicit Compiler(); Compiler();
~Compiler(); ~Compiler();
KJ_DISALLOW_COPY(Compiler); KJ_DISALLOW_COPY(Compiler);
...@@ -76,8 +76,11 @@ public: ...@@ -76,8 +76,11 @@ public:
// use EAGER mode. // use EAGER mode.
}; };
Schema add(Module& module, Mode mode) const; uint64_t add(Module& module, Mode mode) const;
// Add a module to the Compiler, returning its root Schema object. // Add a module to the Compiler, returning the module's file ID. The ID can then be used to
// look up the schema in the SchemaLoader returned by `getLoader()`. However, if there were any
// errors while compiling (reported via `module.addError()`), then the SchemaLoader may behave as
// if the node doesn't exist, or may return an invalid partial Schema.
const SchemaLoader& getLoader() const; const SchemaLoader& getLoader() const;
// Get a SchemaLoader backed by this compiler. Schema nodes will be lazily constructed as you // Get a SchemaLoader backed by this compiler. Schema nodes will be lazily constructed as you
......
...@@ -74,7 +74,9 @@ public: ...@@ -74,7 +74,9 @@ public:
// remove it from the holes, and return its offset (as a multiple of its size). If there // remove it from the holes, and return its offset (as a multiple of its size). If there
// is no such space, returns zero (no hole can be at offset zero, as explained above). // is no such space, returns zero (no hole can be at offset zero, as explained above).
if (holes[lgSize] != 0) { if (lgSize >= KJ_ARRAY_SIZE(holes)) {
return nullptr;
} else if (holes[lgSize] != 0) {
UIntType result = holes[lgSize]; UIntType result = holes[lgSize];
holes[lgSize] = 0; holes[lgSize] = 0;
return result; return result;
...@@ -549,7 +551,7 @@ public: ...@@ -549,7 +551,7 @@ public:
} }
}; };
Top& getTop(); Top& getTop() { return top; }
private: private:
Top top; Top top;
...@@ -835,7 +837,7 @@ public: ...@@ -835,7 +837,7 @@ public:
schema::StructNode::Builder builder) { schema::StructNode::Builder builder) {
// Build the member-info-by-ordinal map. // Build the member-info-by-ordinal map.
MemberInfo root(layout.getTop()); MemberInfo root(layout.getTop());
traverseGroup(members, root); traverseTopOrGroup(members, root);
// Init the root. // Init the root.
root.memberSchemas = builder.initMembers(root.childCount); root.memberSchemas = builder.initMembers(root.childCount);
...@@ -872,6 +874,9 @@ public: ...@@ -872,6 +874,9 @@ public:
translator.compileDefaultDefaultValue(typeBuilder, fieldBuilder.initDefaultValue()); translator.compileDefaultDefaultValue(typeBuilder, fieldBuilder.initDefaultValue());
break; break;
} }
} else {
translator.compileDefaultDefaultValue(typeBuilder, fieldBuilder.initDefaultValue());
}
int lgSize = -1; int lgSize = -1;
switch (typeBuilder.getBody().which()) { switch (typeBuilder.getBody().which()) {
...@@ -906,7 +911,6 @@ public: ...@@ -906,7 +911,6 @@ public:
} else { } else {
fieldBuilder.setOffset(member.fieldScope->addData(lgSize)); fieldBuilder.setOffset(member.fieldScope->addData(lgSize));
} }
}
targetsFlagName = "targetsField"; targetsFlagName = "targetsField";
break; break;
...@@ -1107,13 +1111,17 @@ private: ...@@ -1107,13 +1111,17 @@ private:
} }
uint traverseGroup(List<Declaration>::Reader members, MemberInfo& parent) { uint traverseGroup(List<Declaration>::Reader members, MemberInfo& parent) {
uint minOrdinal = std::numeric_limits<uint>::max();
uint codeOrder = 0;
if (members.size() < 2) { if (members.size() < 2) {
errorReporter.addErrorOn(parent.decl, "Group must have at least two members."); errorReporter.addErrorOn(parent.decl, "Group must have at least two members.");
} }
return traverseTopOrGroup(members, parent);
}
uint traverseTopOrGroup(List<Declaration>::Reader members, MemberInfo& parent) {
uint minOrdinal = std::numeric_limits<uint>::max();
uint codeOrder = 0;
for (auto member: members) { for (auto member: members) {
uint ordinal = 0; uint ordinal = 0;
MemberInfo* memberInfo = nullptr; MemberInfo* memberInfo = nullptr;
...@@ -1122,6 +1130,7 @@ private: ...@@ -1122,6 +1130,7 @@ private:
case Declaration::Body::FIELD_DECL: { case Declaration::Body::FIELD_DECL: {
memberInfo = &arena.allocate<MemberInfo>( memberInfo = &arena.allocate<MemberInfo>(
parent, codeOrder++, member, *parent.fieldScope); parent, codeOrder++, member, *parent.fieldScope);
ordinal = member.getId().getOrdinal().getValue();
break; break;
} }
...@@ -1258,13 +1267,14 @@ bool NodeTranslator::compileType(TypeExpression::Reader source, schema::Type::Bu ...@@ -1258,13 +1267,14 @@ bool NodeTranslator::compileType(TypeExpression::Reader source, schema::Type::Bu
if (source.getParams().size() != 0) { if (source.getParams().size() != 0) {
errorReporter.addErrorOn(source, kj::str( errorReporter.addErrorOn(source, kj::str(
"'", declNameString(name), "' does not accept parameters.")); "'", declNameString(name), "' does not accept parameters."));
}
return false; return false;
} }
}
return true; return true;
} else { } else {
target.getBody().setVoidType();
return false; return false;
} }
} }
...@@ -1305,63 +1315,59 @@ public: ...@@ -1305,63 +1315,59 @@ public:
: type(FIELD), structBuilder(structBuilder), member(member) {} : type(FIELD), structBuilder(structBuilder), member(member) {}
DynamicSlot(DynamicList::Builder listBuilder, uint index) DynamicSlot(DynamicList::Builder listBuilder, uint index)
: type(ELEMENT), listBuilder(listBuilder), index(index) {} : type(ELEMENT), listBuilder(listBuilder), index(index) {}
DynamicSlot(DynamicStruct::Builder structBuilder, StructSchema::Member member, DynamicSlot(DynamicUnion::Builder unionBuilder, StructSchema::Member unionMember)
: type(UNION_MEMBER), unionBuilder(unionBuilder), unionMember(unionMember) {}
DynamicSlot(DynamicUnion::Builder unionBuilder, StructSchema::Member unionMember,
StructSchema structMemberSchema) StructSchema structMemberSchema)
: type(STRUCT_OBJECT_FIELD), structBuilder(structBuilder), member(member), : type(STRUCT_OBJECT_UNION_MEMBER), unionBuilder(unionBuilder), unionMember(unionMember),
structMemberSchema(structMemberSchema) {} structMemberSchema(structMemberSchema) {}
DynamicSlot(DynamicStruct::Builder structBuilder, StructSchema::Member member, DynamicSlot(DynamicUnion::Builder unionBuilder, StructSchema::Member unionMember,
ListSchema listMemberSchema) ListSchema listMemberSchema)
: type(LIST_OBJECT_FIELD), structBuilder(structBuilder), member(member), : type(LIST_OBJECT_UNION_MEMBER), unionBuilder(unionBuilder), unionMember(unionMember),
listMemberSchema(listMemberSchema) {} listMemberSchema(listMemberSchema) {}
DynamicSlot(DynamicUnion::Builder unionBuilder, StructSchema::Member unionMember)
: type(UNION_MEMBER), unionBuilder(unionBuilder), unionMember(unionMember) {}
bool wasSet = false;
DynamicStruct::Builder initStruct() { DynamicStruct::Builder initStruct() {
wasSet = true;
switch (type) { switch (type) {
case FIELD: return structBuilder.init(member).as<DynamicStruct>(); case FIELD: return structBuilder.init(member).as<DynamicStruct>();
case ELEMENT: return listBuilder[index].as<DynamicStruct>(); case ELEMENT: return listBuilder[index].as<DynamicStruct>();
case STRUCT_OBJECT_FIELD: return structBuilder.initObject(member, structMemberSchema);
case LIST_OBJECT_FIELD: KJ_FAIL_REQUIRE("Value type mismatch.");
case UNION_MEMBER: return unionBuilder.init(unionMember).as<DynamicStruct>(); case UNION_MEMBER: return unionBuilder.init(unionMember).as<DynamicStruct>();
case STRUCT_OBJECT_UNION_MEMBER:
return unionBuilder.initObject(unionMember, structMemberSchema);
case LIST_OBJECT_UNION_MEMBER: KJ_FAIL_REQUIRE("Type mismatch.");
} }
KJ_FAIL_ASSERT("can't get here"); KJ_FAIL_ASSERT("can't get here");
} }
DynamicList::Builder initList(uint size) { DynamicList::Builder initList(uint size) {
wasSet = true;
switch (type) { switch (type) {
case FIELD: return structBuilder.init(member, size).as<DynamicList>(); case FIELD: return structBuilder.init(member, size).as<DynamicList>();
case ELEMENT: return listBuilder.init(index, size).as<DynamicList>(); case ELEMENT: return listBuilder.init(index, size).as<DynamicList>();
case STRUCT_OBJECT_FIELD: KJ_FAIL_REQUIRE("Value type mismatch.");
case LIST_OBJECT_FIELD: return structBuilder.initObject(member, listMemberSchema, size);
case UNION_MEMBER: return unionBuilder.init(unionMember, size).as<DynamicList>(); case UNION_MEMBER: return unionBuilder.init(unionMember, size).as<DynamicList>();
case STRUCT_OBJECT_UNION_MEMBER: KJ_FAIL_REQUIRE("Type mismatch.");
case LIST_OBJECT_UNION_MEMBER:
return unionBuilder.initObject(unionMember, listMemberSchema, size);
} }
KJ_FAIL_ASSERT("can't get here"); KJ_FAIL_ASSERT("can't get here");
} }
DynamicUnion::Builder getUnion() { DynamicUnion::Builder getUnion() {
wasSet = true;
switch (type) { switch (type) {
case FIELD: return structBuilder.get(member).as<DynamicUnion>(); case FIELD: return structBuilder.get(member).as<DynamicUnion>();
case ELEMENT: KJ_FAIL_REQUIRE("Value type mismatch."); case ELEMENT: KJ_FAIL_REQUIRE("Type mismatch.");
case STRUCT_OBJECT_FIELD: KJ_FAIL_REQUIRE("Value type mismatch.");
case LIST_OBJECT_FIELD: KJ_FAIL_REQUIRE("Value type mismatch.");
case UNION_MEMBER: return unionBuilder.init(unionMember).as<DynamicUnion>(); case UNION_MEMBER: return unionBuilder.init(unionMember).as<DynamicUnion>();
case STRUCT_OBJECT_UNION_MEMBER: KJ_FAIL_REQUIRE("Type mismatch.");
case LIST_OBJECT_UNION_MEMBER: KJ_FAIL_REQUIRE("Type mismatch.");
} }
KJ_FAIL_ASSERT("can't get here"); KJ_FAIL_ASSERT("can't get here");
} }
void set(DynamicValue::Reader value) { void set(DynamicValue::Reader value) {
wasSet = true;
switch (type) { switch (type) {
case FIELD: return structBuilder.set(member, value); case FIELD: return structBuilder.set(member, value);
case ELEMENT: return listBuilder.set(index, value); case ELEMENT: return listBuilder.set(index, value);
case STRUCT_OBJECT_FIELD: return structBuilder.set(member, value);
case LIST_OBJECT_FIELD: return structBuilder.set(member, value);
case UNION_MEMBER: return unionBuilder.set(unionMember, value); case UNION_MEMBER: return unionBuilder.set(unionMember, value);
case STRUCT_OBJECT_UNION_MEMBER: return unionBuilder.set(unionMember, value);
case LIST_OBJECT_UNION_MEMBER: return unionBuilder.set(unionMember, value);
} }
KJ_FAIL_ASSERT("can't get here"); KJ_FAIL_ASSERT("can't get here");
} }
...@@ -1379,16 +1385,16 @@ public: ...@@ -1379,16 +1385,16 @@ public:
} }
return nullptr; return nullptr;
} }
case STRUCT_OBJECT_FIELD: return nullptr;
case LIST_OBJECT_FIELD: return nullptr;
case UNION_MEMBER: return enumIdForMember(unionMember); case UNION_MEMBER: return enumIdForMember(unionMember);
case STRUCT_OBJECT_UNION_MEMBER: return nullptr;
case LIST_OBJECT_UNION_MEMBER: return nullptr;
} }
KJ_FAIL_ASSERT("can't get here"); KJ_FAIL_ASSERT("can't get here");
} }
private: private:
enum Type { enum Type {
FIELD, ELEMENT, STRUCT_OBJECT_FIELD, LIST_OBJECT_FIELD, UNION_MEMBER FIELD, ELEMENT, UNION_MEMBER, STRUCT_OBJECT_UNION_MEMBER, LIST_OBJECT_UNION_MEMBER
}; };
Type type; Type type;
...@@ -1396,10 +1402,6 @@ private: ...@@ -1396,10 +1402,6 @@ private:
struct { struct {
DynamicStruct::Builder structBuilder; DynamicStruct::Builder structBuilder;
StructSchema::Member member; StructSchema::Member member;
union {
StructSchema structMemberSchema;
ListSchema listMemberSchema;
};
}; };
struct { struct {
DynamicList::Builder listBuilder; DynamicList::Builder listBuilder;
...@@ -1408,6 +1410,10 @@ private: ...@@ -1408,6 +1410,10 @@ private:
struct { struct {
DynamicUnion::Builder unionBuilder; DynamicUnion::Builder unionBuilder;
StructSchema::Member unionMember; StructSchema::Member unionMember;
union {
StructSchema structMemberSchema;
ListSchema listMemberSchema;
};
}; };
}; };
...@@ -1451,6 +1457,10 @@ static kj::StringPtr getValueUnionMemberNameFor(schema::Type::Body::Which type) ...@@ -1451,6 +1457,10 @@ static kj::StringPtr getValueUnionMemberNameFor(schema::Type::Body::Which type)
void NodeTranslator::compileBootstrapValue(ValueExpression::Reader source, void NodeTranslator::compileBootstrapValue(ValueExpression::Reader source,
schema::Type::Reader type, schema::Type::Reader type,
schema::Value::Builder target) { schema::Value::Builder target) {
// Start by filling in a default default value so that if for whatever reason we don't end up
// initializing the value, this won't cause schema validation to fail.
compileDefaultDefaultValue(type, target);
switch (type.getBody().which()) { switch (type.getBody().which()) {
case schema::Type::Body::LIST_TYPE: case schema::Type::Body::LIST_TYPE:
case schema::Type::Body::STRUCT_TYPE: case schema::Type::Body::STRUCT_TYPE:
...@@ -1471,11 +1481,24 @@ void NodeTranslator::compileValue(ValueExpression::Reader source, schema::Type:: ...@@ -1471,11 +1481,24 @@ void NodeTranslator::compileValue(ValueExpression::Reader source, schema::Type::
auto valueUnion = toDynamic(target).get("body").as<DynamicUnion>(); auto valueUnion = toDynamic(target).get("body").as<DynamicUnion>();
auto member = valueUnion.getSchema().getMemberByName( auto member = valueUnion.getSchema().getMemberByName(
getValueUnionMemberNameFor(type.getBody().which())); getValueUnionMemberNameFor(type.getBody().which()));
switch (type.getBody().which()) {
case schema::Type::Body::LIST_TYPE:
KJ_IF_MAYBE(listSchema, makeListSchemaOf(type.getBody().getListType())) {
DynamicSlot slot(valueUnion, member, *listSchema);
compileValue(source, slot, isBootstrap);
}
break;
case schema::Type::Body::STRUCT_TYPE:
KJ_IF_MAYBE(structSchema, resolver.resolveMaybeBootstrapSchema(
type.getBody().getStructType())) {
DynamicSlot slot(valueUnion, member, structSchema->asStruct());
compileValue(source, slot, isBootstrap);
}
break;
default:
DynamicSlot slot(valueUnion, member); DynamicSlot slot(valueUnion, member);
compileValue(source, slot, isBootstrap); compileValue(source, slot, isBootstrap);
if (!slot.wasSet) { break;
// An error should have been reported already. Initialize to a reasonable default.
compileDefaultDefaultValue(type, target);
} }
} }
...@@ -1487,8 +1510,7 @@ void NodeTranslator::compileValue(ValueExpression::Reader src, DynamicSlot& dst, ...@@ -1487,8 +1510,7 @@ void NodeTranslator::compileValue(ValueExpression::Reader src, DynamicSlot& dst,
// way to test for type compatibility without throwing. // way to test for type compatibility without throwing.
KJ_IF_MAYBE(exception, kj::runCatchingExceptions( KJ_IF_MAYBE(exception, kj::runCatchingExceptions(
[&]() { compileValueInner(src, dst, isBootstrap); })) { [&]() { compileValueInner(src, dst, isBootstrap); })) {
errorReporter.addErrorOn(src, exception->getDescription()); errorReporter.addErrorOn(src, "Type mismatch.");
dst.wasSet = false;
} }
} }
...@@ -1499,32 +1521,45 @@ void NodeTranslator::compileValueInner( ...@@ -1499,32 +1521,45 @@ void NodeTranslator::compileValueInner(
auto name = src.getBody().getName(); auto name = src.getBody().getName();
bool isBare = name.getBase().which() == DeclName::Base::RELATIVE_NAME && bool isBare = name.getBase().which() == DeclName::Base::RELATIVE_NAME &&
name.getMemberPath().size() == 0; name.getMemberPath().size() == 0;
bool wasSet = false;
if (isBare) { if (isBare) {
// The name is just a bare identifier. It may be a literal value or an enumerant. // The name is just a bare identifier. It may be a literal value or an enumerant.
kj::StringPtr id = name.getBase().getRelativeName().getValue(); kj::StringPtr id = name.getBase().getRelativeName().getValue();
KJ_IF_MAYBE(enumId, dst.getEnumType()) { KJ_IF_MAYBE(enumId, dst.getEnumType()) {
auto enumSchema = resolver.resolveMaybeBootstrapSchema(*enumId).asEnum(); KJ_IF_MAYBE(enumSchema, resolver.resolveMaybeBootstrapSchema(*enumId)) {
KJ_IF_MAYBE(enumerant, enumSchema.findEnumerantByName(id)) { KJ_IF_MAYBE(enumerant, enumSchema->asEnum().findEnumerantByName(id)) {
dst.set(DynamicEnum(*enumerant)); dst.set(DynamicEnum(*enumerant));
wasSet = true;
}
} else {
// Enum type is broken. We don't want to report a redundant error here, so just assume
// we would have found a matching enumerant.
dst.set(kj::implicitCast<uint16_t>(0));
wasSet = true;
} }
} else { } else {
// Interpret known constant values. // Interpret known constant values.
if (id == "void") { if (id == "void") {
dst.set(Void::VOID); dst.set(Void::VOID);
wasSet = true;
} else if (id == "true") { } else if (id == "true") {
dst.set(true); dst.set(true);
wasSet = true;
} else if (id == "false") { } else if (id == "false") {
dst.set(false); dst.set(false);
wasSet = true;
} else if (id == "nan") { } else if (id == "nan") {
dst.set(std::numeric_limits<double>::quiet_NaN()); dst.set(std::numeric_limits<double>::quiet_NaN());
wasSet = true;
} else if (id == "inf") { } else if (id == "inf") {
dst.set(std::numeric_limits<double>::infinity()); dst.set(std::numeric_limits<double>::infinity());
wasSet = true;
} }
} }
} }
if (!dst.wasSet) { if (!wasSet) {
// Haven't resolved the name yet. Try looking up a constant. // Haven't resolved the name yet. Try looking up a constant.
KJ_IF_MAYBE(constValue, readConstant(src.getBody().getName(), isBootstrap, src)) { KJ_IF_MAYBE(constValue, readConstant(src.getBody().getName(), isBootstrap, src)) {
dst.set(*constValue); dst.set(*constValue);
...@@ -1618,7 +1653,7 @@ void NodeTranslator::copyValue(schema::Value::Reader src, schema::Type::Reader s ...@@ -1618,7 +1653,7 @@ void NodeTranslator::copyValue(schema::Value::Reader src, schema::Type::Reader s
KJ_IF_MAYBE(exception, kj::runCatchingExceptions( KJ_IF_MAYBE(exception, kj::runCatchingExceptions(
[&]() { dstBody.set(dstFieldName, srcBody.get()); })) { [&]() { dstBody.set(dstFieldName, srcBody.get()); })) {
// Exception caught, therefore the types are not compatible. // Exception caught, therefore the types are not compatible.
errorReporter.addErrorOn(errorLocation, exception->getDescription()); errorReporter.addErrorOn(errorLocation, "Type mismatch.");
} }
} else { } else {
KJ_FAIL_ASSERT("Didn't recognize schema::Value::Body type?"); KJ_FAIL_ASSERT("Didn't recognize schema::Value::Body type?");
...@@ -1641,10 +1676,11 @@ kj::Maybe<DynamicValue::Reader> NodeTranslator::readConstant( ...@@ -1641,10 +1676,11 @@ kj::Maybe<DynamicValue::Reader> NodeTranslator::readConstant(
// //
// We need to be very careful not to query this Schema's dependencies because if it is // We need to be very careful not to query this Schema's dependencies because if it is
// a final schema then this query could trigger a lazy load which would deadlock. // a final schema then this query could trigger a lazy load which would deadlock.
Schema constSchema = isBootstrap ? kj::Maybe<Schema> maybeConstSchema = isBootstrap ?
resolver.resolveMaybeBootstrapSchema(resolved->id) : resolver.resolveMaybeBootstrapSchema(resolved->id) :
resolver.resolveFinalSchema(resolved->id); resolver.resolveFinalSchema(resolved->id);
auto constReader = constSchema.getProto().getBody().getConstNode(); KJ_IF_MAYBE(constSchema, maybeConstSchema) {
auto constReader = constSchema->getProto().getBody().getConstNode();
auto constValue = toDynamic(constReader.getValue()).get("body").as<DynamicUnion>().get(); auto constValue = toDynamic(constReader.getValue()).get("body").as<DynamicUnion>().get();
if (constValue.getType() == DynamicValue::OBJECT) { if (constValue.getType() == DynamicValue::OBJECT) {
...@@ -1653,11 +1689,21 @@ kj::Maybe<DynamicValue::Reader> NodeTranslator::readConstant( ...@@ -1653,11 +1689,21 @@ kj::Maybe<DynamicValue::Reader> NodeTranslator::readConstant(
auto constType = constReader.getType(); auto constType = constReader.getType();
switch (constType.getBody().which()) { switch (constType.getBody().which()) {
case schema::Type::Body::STRUCT_TYPE: case schema::Type::Body::STRUCT_TYPE:
constValue = objValue.as(resolver.resolveMaybeBootstrapSchema( KJ_IF_MAYBE(structSchema, resolver.resolveMaybeBootstrapSchema(
constType.getBody().getStructType()).asStruct()); constType.getBody().getStructType())) {
constValue = objValue.as(structSchema->asStruct());
} else {
// The struct's schema is broken for reasons already reported.
return nullptr;
}
break; break;
case schema::Type::Body::LIST_TYPE: case schema::Type::Body::LIST_TYPE:
constValue = objValue.as(makeListSchemaOf(constType.getBody().getListType())); KJ_IF_MAYBE(listSchema, makeListSchemaOf(constType.getBody().getListType())) {
constValue = objValue.as(*listSchema);
} else {
// The list's schema is broken for reasons already reported.
return nullptr;
}
break; break;
case schema::Type::Body::OBJECT_TYPE: case schema::Type::Body::OBJECT_TYPE:
// Fine as-is. // Fine as-is.
...@@ -1673,8 +1719,9 @@ kj::Maybe<DynamicValue::Reader> NodeTranslator::readConstant( ...@@ -1673,8 +1719,9 @@ kj::Maybe<DynamicValue::Reader> NodeTranslator::readConstant(
// A fully unqualified identifier looks like it might refer to a constant visible in the // A fully unqualified identifier looks like it might refer to a constant visible in the
// current scope, but if that's really what the user wanted, we want them to use a // current scope, but if that's really what the user wanted, we want them to use a
// qualified name to make it more obvious. Report an error. // qualified name to make it more obvious. Report an error.
Schema scope = resolver.resolveMaybeBootstrapSchema(constSchema.getProto().getScopeId()); KJ_IF_MAYBE(scope, resolver.resolveMaybeBootstrapSchema(
auto scopeReader = scope.getProto(); constSchema->getProto().getScopeId())) {
auto scopeReader = scope->getProto();
kj::StringPtr parent; kj::StringPtr parent;
if (scopeReader.getBody().which() == schema::Node::Body::FILE_NODE) { if (scopeReader.getBody().which() == schema::Node::Body::FILE_NODE) {
parent = ""; parent = "";
...@@ -1688,25 +1735,46 @@ kj::Maybe<DynamicValue::Reader> NodeTranslator::readConstant( ...@@ -1688,25 +1735,46 @@ kj::Maybe<DynamicValue::Reader> NodeTranslator::readConstant(
declNameString(name), "' with '", parent, ".", id, declNameString(name), "' with '", parent, ".", id,
"', if that's what you intended.")); "', if that's what you intended."));
} }
}
return constValue; return constValue;
} else { } else {
// The target is a constant, but the constant's schema is broken for reasons already reported.
return nullptr;
}
} else {
// Lookup will have reported an error.
return nullptr; return nullptr;
} }
} }
ListSchema NodeTranslator::makeListSchemaOf(schema::Type::Reader elementType) { kj::Maybe<ListSchema> NodeTranslator::makeListSchemaOf(schema::Type::Reader elementType) {
auto body = elementType.getBody(); auto body = elementType.getBody();
switch (body.which()) { switch (body.which()) {
case schema::Type::Body::ENUM_TYPE: case schema::Type::Body::ENUM_TYPE:
return ListSchema::of(resolver.resolveMaybeBootstrapSchema(body.getEnumType()).asEnum()); KJ_IF_MAYBE(enumSchema, resolver.resolveMaybeBootstrapSchema(body.getEnumType())) {
return ListSchema::of(enumSchema->asEnum());
} else {
return nullptr;
}
case schema::Type::Body::STRUCT_TYPE: case schema::Type::Body::STRUCT_TYPE:
return ListSchema::of(resolver.resolveMaybeBootstrapSchema(body.getStructType()).asStruct()); KJ_IF_MAYBE(structSchema, resolver.resolveMaybeBootstrapSchema(body.getStructType())) {
return ListSchema::of(structSchema->asStruct());
} else {
return nullptr;
}
case schema::Type::Body::INTERFACE_TYPE: case schema::Type::Body::INTERFACE_TYPE:
return ListSchema::of(resolver.resolveMaybeBootstrapSchema(body.getInterfaceType()) KJ_IF_MAYBE(interfaceSchema, resolver.resolveMaybeBootstrapSchema(body.getInterfaceType())) {
.asInterface()); return ListSchema::of(interfaceSchema->asInterface());
} else {
return nullptr;
}
case schema::Type::Body::LIST_TYPE: case schema::Type::Body::LIST_TYPE:
return ListSchema::of(makeListSchemaOf(body.getListType())); KJ_IF_MAYBE(listSchema, makeListSchemaOf(body.getListType())) {
return ListSchema::of(*listSchema);
} else {
return nullptr;
}
default: default:
return ListSchema::of(body.which()); return ListSchema::of(body.which());
} }
...@@ -1727,6 +1795,10 @@ Orphan<List<schema::Annotation>> NodeTranslator::compileAnnotationApplications( ...@@ -1727,6 +1795,10 @@ Orphan<List<schema::Annotation>> NodeTranslator::compileAnnotationApplications(
for (uint i = 0; i < annotations.size(); i++) { for (uint i = 0; i < annotations.size(); i++) {
Declaration::AnnotationApplication::Reader annotation = annotations[i]; Declaration::AnnotationApplication::Reader annotation = annotations[i];
schema::Annotation::Builder annotationBuilder = builder[i]; schema::Annotation::Builder annotationBuilder = builder[i];
// Set the annotation's value to void in case we fail to produce something better below.
annotationBuilder.initValue().getBody().setVoidValue();
auto name = annotation.getName(); auto name = annotation.getName();
KJ_IF_MAYBE(decl, resolver.resolve(name)) { KJ_IF_MAYBE(decl, resolver.resolve(name)) {
if (decl->kind != Declaration::Body::ANNOTATION_DECL) { if (decl->kind != Declaration::Body::ANNOTATION_DECL) {
...@@ -1734,8 +1806,8 @@ Orphan<List<schema::Annotation>> NodeTranslator::compileAnnotationApplications( ...@@ -1734,8 +1806,8 @@ Orphan<List<schema::Annotation>> NodeTranslator::compileAnnotationApplications(
"'", declNameString(name), "' is not an annotation.")); "'", declNameString(name), "' is not an annotation."));
} else { } else {
annotationBuilder.setId(decl->id); annotationBuilder.setId(decl->id);
auto node = resolver.resolveMaybeBootstrapSchema(decl->id).getProto() KJ_IF_MAYBE(annotationSchema, resolver.resolveMaybeBootstrapSchema(decl->id)) {
.getBody().getAnnotationNode(); auto node = annotationSchema->getProto().getBody().getAnnotationNode();
if (!toDynamic(node).get(targetsFlagName).as<bool>()) { if (!toDynamic(node).get(targetsFlagName).as<bool>()) {
errorReporter.addErrorOn(name, kj::str( errorReporter.addErrorOn(name, kj::str(
"'", declNameString(name), "' cannot be applied to this kind of declaration.")); "'", declNameString(name), "' cannot be applied to this kind of declaration."));
...@@ -1747,20 +1819,20 @@ Orphan<List<schema::Annotation>> NodeTranslator::compileAnnotationApplications( ...@@ -1747,20 +1819,20 @@ Orphan<List<schema::Annotation>> NodeTranslator::compileAnnotationApplications(
case Declaration::AnnotationApplication::Value::NONE: case Declaration::AnnotationApplication::Value::NONE:
// No value, i.e. void. // No value, i.e. void.
if (node.getType().getBody().which() == schema::Type::Body::VOID_TYPE) { if (node.getType().getBody().which() == schema::Type::Body::VOID_TYPE) {
annotationBuilder.initValue().getBody().setVoidValue(); annotationBuilder.getValue().getBody().setVoidValue();
} else { } else {
errorReporter.addErrorOn(name, kj::str( errorReporter.addErrorOn(name, kj::str(
"'", declNameString(name), "' requires a value.")); "'", declNameString(name), "' requires a value."));
compileDefaultDefaultValue(node.getType(), annotationBuilder.initValue()); compileDefaultDefaultValue(node.getType(), annotationBuilder.getValue());
} }
break; break;
case Declaration::AnnotationApplication::Value::EXPRESSION: case Declaration::AnnotationApplication::Value::EXPRESSION:
compileBootstrapValue(value.getExpression(), node.getType(), compileBootstrapValue(value.getExpression(), node.getType(),
annotationBuilder.initValue()); annotationBuilder.getValue());
break; break;
} }
}
} }
} }
} }
......
...@@ -54,15 +54,17 @@ public: ...@@ -54,15 +54,17 @@ public:
// Look up the given name, relative to this node, and return basic information about the // Look up the given name, relative to this node, and return basic information about the
// target. // target.
virtual Schema resolveMaybeBootstrapSchema(uint64_t id) const = 0; virtual kj::Maybe<Schema> resolveMaybeBootstrapSchema(uint64_t id) const = 0;
// Get the schema for the given ID. Returning either a bootstrap schema or a final schema // Get the schema for the given ID. Returning either a bootstrap schema or a final schema
// is acceptable. Throws an exception if the id is not one that was found by calling resolve() // is acceptable. Throws an exception if the id is not one that was found by calling resolve()
// or by traversing other schemas. // or by traversing other schemas. Returns null if the ID is recognized, but the corresponding
// schema node failed to be built for reasons that were already reported.
virtual Schema resolveFinalSchema(uint64_t id) const = 0; virtual kj::Maybe<Schema> resolveFinalSchema(uint64_t id) const = 0;
// Get the final schema for the given ID. A bootstrap schema is not acceptable. Throws an // Get the final schema for the given ID. A bootstrap schema is not acceptable. Throws an
// exception if the id is not one that was found by calling resolve() or by traversing other // exception if the id is not one that was found by calling resolve() or by traversing other
// schemas. // schemas. Returns null if the ID is recognized, but the corresponding schema node failed to
// be built for reasons that were already reported.
}; };
NodeTranslator(const Resolver& resolver, const ErrorReporter& errorReporter, NodeTranslator(const Resolver& resolver, const ErrorReporter& errorReporter,
...@@ -162,10 +164,12 @@ private: ...@@ -162,10 +164,12 @@ private:
kj::Maybe<DynamicValue::Reader> readConstant(DeclName::Reader name, bool isBootstrap, kj::Maybe<DynamicValue::Reader> readConstant(DeclName::Reader name, bool isBootstrap,
ValueExpression::Reader errorLocation); ValueExpression::Reader errorLocation);
// Get the value of the given constant. // Get the value of the given constant. May return null if some error occurs, which will already
// have been reported.
ListSchema makeListSchemaOf(schema::Type::Reader elementType); kj::Maybe<ListSchema> makeListSchemaOf(schema::Type::Reader elementType);
// Construct a list schema representing a list of elements of the given type. // Construct a list schema representing a list of elements of the given type. May return null if
// some error occurs, which will already have been reported.
Orphan<List<schema::Annotation>> compileAnnotationApplications( Orphan<List<schema::Annotation>> compileAnnotationApplications(
List<Declaration::AnnotationApplication>::Reader annotations, List<Declaration::AnnotationApplication>::Reader annotations,
......
...@@ -1585,7 +1585,7 @@ struct WireHelpers { ...@@ -1585,7 +1585,7 @@ struct WireHelpers {
} }
static void adopt(SegmentBuilder* segment, WirePointer* ref, OrphanBuilder&& value) { static void adopt(SegmentBuilder* segment, WirePointer* ref, OrphanBuilder&& value) {
KJ_REQUIRE(value.segment->getArena() == segment->getArena(), KJ_REQUIRE(value.segment == nullptr || value.segment->getArena() == segment->getArena(),
"Adopted object must live in the same message."); "Adopted object must live in the same message.");
if (!ref->isNull()) { if (!ref->isNull()) {
......
...@@ -733,7 +733,7 @@ public: ...@@ -733,7 +733,7 @@ public:
KJ_DISALLOW_COPY(Deferred); KJ_DISALLOW_COPY(Deferred);
// This move constructor is usually optimized away by the compiler. // This move constructor is usually optimized away by the compiler.
inline Deferred(Deferred&& other): func(kj::mv(other.func)) { inline Deferred(Deferred&& other): func(kj::mv(other.func)), canceled(false) {
other.canceled = true; other.canceled = true;
} }
private: private:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment