Commit a45c463c authored by Kenton Varda's avatar Kenton Varda

Various tweaks.

parent d92038eb
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
class CoutErrorReporter: public capnp::compiler::ErrorReporter { class CoutErrorReporter: public capnp::compiler::ErrorReporter {
public: public:
void addError(uint32_t startByte, uint32_t endByte, kj::String message) override { void addError(uint32_t startByte, uint32_t endByte, kj::StringPtr message) override {
std::cout << "input:" << startByte << "-" << endByte << ": " << message.cStr() << std::endl; std::cout << "input:" << startByte << "-" << endByte << ": " << message.cStr() << std::endl;
} }
}; };
......
...@@ -34,7 +34,7 @@ class ErrorReporter { ...@@ -34,7 +34,7 @@ class ErrorReporter {
public: public:
virtual ~ErrorReporter() noexcept(false); virtual ~ErrorReporter() noexcept(false);
virtual void addError(uint32_t startByte, uint32_t endByte, kj::String message) = 0; virtual void addError(uint32_t startByte, uint32_t endByte, kj::StringPtr message) = 0;
// Report an error at the given location in the input text. `startByte` and `endByte` indicate // Report an error at the given location in the input text. `startByte` and `endByte` indicate
// the span of text that is erroneous. They may be equal, in which case the parser was only // the span of text that is erroneous. They may be equal, in which case the parser was only
// able to identify where the error begins, not where it ends. // able to identify where the error begins, not where it ends.
......
...@@ -66,7 +66,7 @@ void parseFile(List<Statement>::Reader statements, ParsedFile::Builder result, ...@@ -66,7 +66,7 @@ void parseFile(List<Statement>::Reader statements, ParsedFile::Builder result,
case Declaration::Body::NAKED_ID: case Declaration::Body::NAKED_ID:
if (fileDecl.getId().which() == Declaration::Id::UID) { if (fileDecl.getId().which() == Declaration::Id::UID) {
errorReporter.addError(builder.getStartByte(), builder.getEndByte(), errorReporter.addError(builder.getStartByte(), builder.getEndByte(),
kj::str("File can only have one ID.")); "File can only have one ID.");
} else { } else {
fileDecl.getId().adoptUid(body.disownNakedId()); fileDecl.getId().adoptUid(body.disownNakedId());
if (builder.hasDocComment()) { if (builder.hasDocComment()) {
...@@ -219,20 +219,17 @@ public: ...@@ -219,20 +219,17 @@ public:
if (best < item.end()) { if (best < item.end()) {
// Report error from the point where parsing failed to the end of the item. // Report error from the point where parsing failed to the end of the item.
errorReporter.addError( errorReporter.addError(
best->getStartByte(), (item.end() - 1)->getEndByte(), best->getStartByte(), (item.end() - 1)->getEndByte(), "Parse error.");
kj::str("Parse error."));
} else if (item.size() > 0) { } else if (item.size() > 0) {
// The item is non-empty and the parser consumed all of it before failing. Report an // The item is non-empty and the parser consumed all of it before failing. Report an
// error for the whole thing. // error for the whole thing.
errorReporter.addError( errorReporter.addError(
item.begin()->getStartByte(), (item.end() - 1)->getEndByte(), item.begin()->getStartByte(), (item.end() - 1)->getEndByte(), "Parse error.");
kj::str("Parse error."));
} else { } else {
// The item has no content. // The item has no content.
// TODO(cleanup): We don't actually know the item's location, so we can only report // TODO(cleanup): We don't actually know the item's location, so we can only report
// an error across the whole list. Fix this. // an error across the whole list. Fix this.
errorReporter.addError(items.startByte, items.endByte, errorReporter.addError(items.startByte, items.endByte, "Parse error: Empty list item.");
kj::str("Parse error: Empty list item."));
} }
} }
} }
...@@ -412,7 +409,7 @@ CapnpParser::CapnpParser(Orphanage orphanageParam, ErrorReporter& errorReporterP ...@@ -412,7 +409,7 @@ CapnpParser::CapnpParser(Orphanage orphanageParam, ErrorReporter& errorReporterP
} else { } else {
auto fieldValue = field->get().getValue(); auto fieldValue = field->get().getValue();
errorReporter.addError(fieldValue.getStartByte(), fieldValue.getEndByte(), errorReporter.addError(fieldValue.getStartByte(), fieldValue.getEndByte(),
kj::str("Missing field name.")); "Missing field name.");
} }
} }
} }
...@@ -511,7 +508,7 @@ CapnpParser::CapnpParser(Orphanage orphanageParam, ErrorReporter& errorReporterP ...@@ -511,7 +508,7 @@ CapnpParser::CapnpParser(Orphanage orphanageParam, ErrorReporter& errorReporterP
} else { } else {
auto fieldValue = field->get().getValue(); auto fieldValue = field->get().getValue();
errorReporter.addError(fieldValue.getStartByte(), fieldValue.getEndByte(), errorReporter.addError(fieldValue.getStartByte(), fieldValue.getEndByte(),
kj::str("Missing field name.")); "Missing field name.");
} }
} }
} }
...@@ -541,7 +538,7 @@ CapnpParser::CapnpParser(Orphanage orphanageParam, ErrorReporter& errorReporterP ...@@ -541,7 +538,7 @@ CapnpParser::CapnpParser(Orphanage orphanageParam, ErrorReporter& errorReporterP
[this](Located<uint64_t>&& value) { [this](Located<uint64_t>&& value) {
if (value.value < (1ull << 63)) { if (value.value < (1ull << 63)) {
errorReporter.addError(value.startByte, value.endByte, errorReporter.addError(value.startByte, value.endByte,
kj::str("Invalid ID. Please generate a new one with 'capnpc -i'.")); "Invalid ID. Please generate a new one with 'capnpc -i'.");
} }
return value.asProto<LocatedInteger>(orphanage); return value.asProto<LocatedInteger>(orphanage);
})); }));
...@@ -551,7 +548,7 @@ CapnpParser::CapnpParser(Orphanage orphanageParam, ErrorReporter& errorReporterP ...@@ -551,7 +548,7 @@ CapnpParser::CapnpParser(Orphanage orphanageParam, ErrorReporter& errorReporterP
[this](Located<uint64_t>&& value) { [this](Located<uint64_t>&& value) {
if (value.value >= 65536) { if (value.value >= 65536) {
errorReporter.addError(value.startByte, value.endByte, errorReporter.addError(value.startByte, value.endByte,
kj::str("Ordinals cannot be greater than 65535.")); "Ordinals cannot be greater than 65535.");
} }
return value.asProto<LocatedInteger>(orphanage); return value.asProto<LocatedInteger>(orphanage);
})); }));
...@@ -778,7 +775,7 @@ CapnpParser::CapnpParser(Orphanage orphanageParam, ErrorReporter& errorReporterP ...@@ -778,7 +775,7 @@ CapnpParser::CapnpParser(Orphanage orphanageParam, ErrorReporter& errorReporterP
// Set all. // Set all.
if (targets.value.size() > 1) { if (targets.value.size() > 1) {
errorReporter.addError(target->startByte, target->endByte, errorReporter.addError(target->startByte, target->endByte,
kj::str("Wildcard should not be specified together with other targets.")); "Wildcard should not be specified together with other targets.");
} }
for (auto member: dynamicBuilder.getSchema().getMembers()) { for (auto member: dynamicBuilder.getSchema().getMembers()) {
...@@ -790,7 +787,7 @@ CapnpParser::CapnpParser(Orphanage orphanageParam, ErrorReporter& errorReporterP ...@@ -790,7 +787,7 @@ CapnpParser::CapnpParser(Orphanage orphanageParam, ErrorReporter& errorReporterP
if (target->value.size() == 0 || target->value.size() >= 32 || if (target->value.size() == 0 || target->value.size() >= 32 ||
target->value[0] < 'a' || target->value[0] > 'z') { target->value[0] < 'a' || target->value[0] > 'z') {
errorReporter.addError(target->startByte, target->endByte, errorReporter.addError(target->startByte, target->endByte,
kj::str("Not a valid annotation target.")); "Not a valid annotation target.");
} else { } else {
char buffer[64]; char buffer[64];
strcpy(buffer, "targets"); strcpy(buffer, "targets");
...@@ -799,12 +796,12 @@ CapnpParser::CapnpParser(Orphanage orphanageParam, ErrorReporter& errorReporterP ...@@ -799,12 +796,12 @@ CapnpParser::CapnpParser(Orphanage orphanageParam, ErrorReporter& errorReporterP
KJ_IF_MAYBE(member, dynamicBuilder.getSchema().findMemberByName(buffer)) { KJ_IF_MAYBE(member, dynamicBuilder.getSchema().findMemberByName(buffer)) {
if (dynamicBuilder.get(*member).as<bool>()) { if (dynamicBuilder.get(*member).as<bool>()) {
errorReporter.addError(target->startByte, target->endByte, errorReporter.addError(target->startByte, target->endByte,
kj::str("Duplicate target specification.")); "Duplicate target specification.");
} }
dynamicBuilder.set(*member, true); dynamicBuilder.set(*member, true);
} else { } else {
errorReporter.addError(target->startByte, target->endByte, errorReporter.addError(target->startByte, target->endByte,
kj::str("Not a valid annotation target.")); "Not a valid annotation target.");
} }
} }
} }
...@@ -866,7 +863,7 @@ kj::Maybe<Orphan<Declaration>> CapnpParser::parseStatement( ...@@ -866,7 +863,7 @@ kj::Maybe<Orphan<Declaration>> CapnpParser::parseStatement(
case Statement::Block::NONE: case Statement::Block::NONE:
if (output->memberParser != nullptr) { if (output->memberParser != nullptr) {
errorReporter.addError(statement.getStartByte(), statement.getEndByte(), errorReporter.addError(statement.getStartByte(), statement.getEndByte(),
kj::str("This statement should end with a semicolon, not a block.")); "This statement should end with a semicolon, not a block.");
} }
break; break;
...@@ -882,7 +879,7 @@ kj::Maybe<Orphan<Declaration>> CapnpParser::parseStatement( ...@@ -882,7 +879,7 @@ kj::Maybe<Orphan<Declaration>> CapnpParser::parseStatement(
builder.adoptNestedDecls(arrayToList(orphanage, members.releaseAsArray())); builder.adoptNestedDecls(arrayToList(orphanage, members.releaseAsArray()));
} else { } else {
errorReporter.addError(statement.getStartByte(), statement.getEndByte(), errorReporter.addError(statement.getStartByte(), statement.getEndByte(),
kj::str("This statement should end with a block, not a semicolon.")); "This statement should end with a block, not a semicolon.");
} }
break; break;
} }
...@@ -902,7 +899,7 @@ kj::Maybe<Orphan<Declaration>> CapnpParser::parseStatement( ...@@ -902,7 +899,7 @@ kj::Maybe<Orphan<Declaration>> CapnpParser::parseStatement(
bestByte = 0; bestByte = 0;
} }
errorReporter.addError(bestByte, bestByte, kj::str("Parse error.")); errorReporter.addError(bestByte, bestByte, "Parse error.");
return nullptr; return nullptr;
} }
} }
......
...@@ -263,7 +263,7 @@ public: ...@@ -263,7 +263,7 @@ public:
EXPECT_EQ(node.getId(), id); EXPECT_EQ(node.getId(), id);
EXPECT_FALSE(loaded); EXPECT_FALSE(loaded);
loaded = true; loaded = true;
loader.loadIfNew(node); loader.loadOnce(node);
} }
private: private:
......
...@@ -1213,7 +1213,7 @@ Schema SchemaLoader::load(const schema::Node::Reader& reader) { ...@@ -1213,7 +1213,7 @@ Schema SchemaLoader::load(const schema::Node::Reader& reader) {
return Schema(impl.lock()->get()->load(reader, false)); return Schema(impl.lock()->get()->load(reader, false));
} }
Schema SchemaLoader::loadIfNew(const schema::Node::Reader& reader) const { Schema SchemaLoader::loadOnce(const schema::Node::Reader& reader) const {
auto locked = impl.lock(); auto locked = impl.lock();
auto getResult = locked->get()->tryGet(reader.getId()); auto getResult = locked->get()->tryGet(reader.getId());
if (getResult.schema == nullptr || getResult.schema->lazyInitializer != nullptr) { if (getResult.schema == nullptr || getResult.schema->lazyInitializer != nullptr) {
......
...@@ -36,7 +36,7 @@ public: ...@@ -36,7 +36,7 @@ public:
public: public:
virtual void load(const SchemaLoader& loader, uint64_t id) const = 0; virtual void load(const SchemaLoader& loader, uint64_t id) const = 0;
// Request that the schema node with the given ID be loaded into the given SchemaLoader. If // Request that the schema node with the given ID be loaded into the given SchemaLoader. If
// the callback is able to find a schema for this ID, it should invoke `loadIfNew()` on // the callback is able to find a schema for this ID, it should invoke `loadOnce()` on
// `loader` to load it. If no such node exists, it should simply do nothing and return. // `loader` to load it. If no such node exists, it should simply do nothing and return.
// //
// The callback is allowed to load schema nodes other than the one requested, e.g. because it // The callback is allowed to load schema nodes other than the one requested, e.g. because it
...@@ -101,10 +101,12 @@ public: ...@@ -101,10 +101,12 @@ public:
// Also note that unknown types are not considered invalid. Instead, the dynamic API returns // Also note that unknown types are not considered invalid. Instead, the dynamic API returns
// a DynamicValue with type UNKNOWN for these. // a DynamicValue with type UNKNOWN for these.
Schema loadIfNew(const schema::Node::Reader& reader) const; Schema loadOnce(const schema::Node::Reader& reader) const;
// Like `load()` but does nothing if a schema with the same ID is already loaded. In contrast, // Like `load()` but does nothing if a schema with the same ID is already loaded. In contrast,
// `load()` would attempt to compare the schemas and take the newer one. `loadIfNew()` is safe // `load()` would attempt to compare the schemas and take the newer one. `loadOnce()` is safe
// to call even while concurrently using schemas from this loader. // to call even while concurrently using schemas from this loader. It should be considered an
// error to call `loadOnce()` with two non-identical schemas that share the same ID, although
// this error may or may not actually be detected by the implementation.
template <typename T> template <typename T>
void loadCompiledTypeAndDependencies(); void loadCompiledTypeAndDependencies();
......
...@@ -732,8 +732,7 @@ public: ...@@ -732,8 +732,7 @@ public:
inline ~Deferred() { if (!canceled) func(); } inline ~Deferred() { if (!canceled) func(); }
KJ_DISALLOW_COPY(Deferred); KJ_DISALLOW_COPY(Deferred);
// This move constructor is optimized away by the compiler in practice. It is only here for // This move constructor is usually optimized away by the compiler.
// technical correctness.
inline Deferred(Deferred&& other): func(kj::mv(other.func)) { inline Deferred(Deferred&& other): func(kj::mv(other.func)) {
other.canceled = true; other.canceled = true;
} }
...@@ -742,14 +741,22 @@ private: ...@@ -742,14 +741,22 @@ private:
bool canceled; bool canceled;
}; };
} // namespace _ (private)
template <typename Func> template <typename Func>
Deferred<Decay<Func>> defer(Func&& func) { _::Deferred<Decay<Func>> defer(Func&& func) {
return Deferred<Decay<Func>>(kj::fwd<Func>(func)); // Returns an object which will invoke the given functor in its destructor. The object is not
} // copyable but is movable with the semantics you'd expect. Since the return type is private,
// you need to assign to an `auto` variable.
//
// The KJ_DEFER macro provides slightly more convenient syntax for the common case where you
// want some code to run at function exit.
} // namespace _ (private) return _::Deferred<Decay<Func>>(kj::fwd<Func>(func));
}
#define KJ_DEFER(code) auto KJ_UNIQUE_NAME(_kjDefer) = ::kj::_::defer([&](){code;}) #define KJ_DEFER(code) auto KJ_UNIQUE_NAME(_kjDefer) = ::kj::defer([&](){code;})
// Run the given code when the function exits, whether by return or exception.
} // namespace kj } // namespace kj
......
...@@ -153,6 +153,11 @@ public: ...@@ -153,6 +153,11 @@ public:
// Lock the value for read-only access. Multiple read-only locks can be taken concurrently, as // Lock the value for read-only access. Multiple read-only locks can be taken concurrently, as
// long as there are no writers. // long as there are no writers.
inline const T& getWithoutLock() const { return value; }
inline T& getWithoutLock() { return value; }
// Escape hatch for cases where some external factor guarantees that it's safe to get the
// value. You should treat these like const_cast -- be highly suspicious of any use.
private: private:
mutable _::Mutex mutex; mutable _::Mutex mutex;
mutable T value; mutable T value;
......
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