Commit 3b0e4f1e authored by Kenton Varda's avatar Kenton Varda

Update capnpc-capnp to use KJ_MAIN.

parent 10697ea1
...@@ -41,6 +41,12 @@ ...@@ -41,6 +41,12 @@
#include <capnp/serialize-packed.h> #include <capnp/serialize-packed.h>
#include <limits> #include <limits>
#if HAVE_CONFIG_H
#include "config.h"
#else
#define VERSION "(unknown ekam build)"
#endif
namespace capnp { namespace capnp {
namespace compiler { namespace compiler {
...@@ -65,7 +71,7 @@ public: ...@@ -65,7 +71,7 @@ public:
} }
}; };
static const char VERSION_STRING[] = "Cap'n Proto version 0.2"; static const char VERSION_STRING[] = "Cap'n Proto version " VERSION;
class CompilerMain final: public GlobalErrorReporter { class CompilerMain final: public GlobalErrorReporter {
public: public:
......
...@@ -29,11 +29,18 @@ ...@@ -29,11 +29,18 @@
#include <kj/debug.h> #include <kj/debug.h>
#include <kj/io.h> #include <kj/io.h>
#include <kj/string-tree.h> #include <kj/string-tree.h>
#include <kj/vector.h>
#include "../schema-loader.h" #include "../schema-loader.h"
#include "../dynamic.h" #include "../dynamic.h"
#include <unistd.h> #include <unistd.h>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <kj/main.h>
#if HAVE_CONFIG_H
#include "config.h"
#else
#define VERSION "(unknown ekam build)"
#endif
namespace capnp { namespace capnp {
namespace { namespace {
...@@ -70,431 +77,446 @@ inline Indent KJ_STRINGIFY(const Indent& indent) { ...@@ -70,431 +77,446 @@ inline Indent KJ_STRINGIFY(const Indent& indent) {
// ======================================================================================= // =======================================================================================
SchemaLoader schemaLoader; class CapnpcCapnpMain {
public:
CapnpcCapnpMain(kj::ProcessContext& context): context(context) {}
kj::MainFunc getMain() {
return kj::MainBuilder(context, "Cap'n Proto loopback plugin version " VERSION,
"This is a Cap'n Proto compiler plugin which \"de-compiles\" the schema back into "
"Cap'n Proto schema language format, with comments showing the offsets chosen by the "
"compiler. This is meant to be run using the Cap'n Proto compiler, e.g.:\n"
" capnp compile -ocapnp foo.capnp")
.callAfterParsing(KJ_BIND_METHOD(*this, run))
.build();
}
Text::Reader getUnqualifiedName(Schema schema) { private:
auto proto = schema.getProto(); kj::ProcessContext& context;
KJ_CONTEXT(proto.getDisplayName()); SchemaLoader schemaLoader;
auto parent = schemaLoader.get(proto.getScopeId());
for (auto nested: parent.getProto().getNestedNodes()) { Text::Reader getUnqualifiedName(Schema schema) {
if (nested.getId() == proto.getId()) { auto proto = schema.getProto();
return nested.getName(); KJ_CONTEXT(proto.getDisplayName());
auto parent = schemaLoader.get(proto.getScopeId());
for (auto nested: parent.getProto().getNestedNodes()) {
if (nested.getId() == proto.getId()) {
return nested.getName();
}
} }
KJ_FAIL_REQUIRE("A schema Node's supposed scope did not contain the node as a NestedNode.");
return "(?)";
} }
KJ_FAIL_REQUIRE("A schema Node's supposed scope did not contain the node as a NestedNode.");
return "(?)";
}
kj::StringTree nodeName(Schema target, Schema scope) { kj::StringTree nodeName(Schema target, Schema scope) {
std::vector<Schema> targetParents; kj::Vector<Schema> targetParents;
std::vector<Schema> scopeParts; kj::Vector<Schema> scopeParts;
{ {
Schema parent = target; Schema parent = target;
while (parent.getProto().getScopeId() != 0) { while (parent.getProto().getScopeId() != 0) {
parent = schemaLoader.get(parent.getProto().getScopeId()); parent = schemaLoader.get(parent.getProto().getScopeId());
targetParents.push_back(parent); targetParents.add(parent);
}
} }
}
{ {
Schema parent = scope; Schema parent = scope;
scopeParts.push_back(parent); scopeParts.add(parent);
while (parent.getProto().getScopeId() != 0) { while (parent.getProto().getScopeId() != 0) {
parent = schemaLoader.get(parent.getProto().getScopeId()); parent = schemaLoader.get(parent.getProto().getScopeId());
scopeParts.push_back(parent); scopeParts.add(parent);
}
} }
}
// Remove common scope. // Remove common scope.
while (!scopeParts.empty() && !targetParents.empty() && while (!scopeParts.empty() && !targetParents.empty() &&
scopeParts.back() == targetParents.back()) { scopeParts.back() == targetParents.back()) {
scopeParts.pop_back(); scopeParts.removeLast();
targetParents.pop_back(); targetParents.removeLast();
} }
// TODO(someday): This is broken in that we aren't checking for shadowing. // TODO(someday): This is broken in that we aren't checking for shadowing.
kj::StringTree path = kj::strTree(); kj::StringTree path = kj::strTree();
while (!targetParents.empty()) { while (!targetParents.empty()) {
auto part = targetParents.back(); auto part = targetParents.back();
auto proto = part.getProto(); auto proto = part.getProto();
if (proto.getScopeId() == 0) { if (proto.getScopeId() == 0) {
path = kj::strTree(kj::mv(path), "import \"/", proto.getDisplayName(), "\"."); path = kj::strTree(kj::mv(path), "import \"/", proto.getDisplayName(), "\".");
} else { } else {
path = kj::strTree(kj::mv(path), getUnqualifiedName(part), "."); path = kj::strTree(kj::mv(path), getUnqualifiedName(part), ".");
}
targetParents.removeLast();
} }
targetParents.pop_back();
}
return kj::strTree(kj::mv(path), getUnqualifiedName(target)); return kj::strTree(kj::mv(path), getUnqualifiedName(target));
}
kj::StringTree genType(schema::Type::Reader type, Schema scope) {
auto body = type.getBody();
switch (body.which()) {
case schema::Type::Body::VOID_TYPE: return kj::strTree("Void");
case schema::Type::Body::BOOL_TYPE: return kj::strTree("Bool");
case schema::Type::Body::INT8_TYPE: return kj::strTree("Int8");
case schema::Type::Body::INT16_TYPE: return kj::strTree("Int16");
case schema::Type::Body::INT32_TYPE: return kj::strTree("Int32");
case schema::Type::Body::INT64_TYPE: return kj::strTree("Int64");
case schema::Type::Body::UINT8_TYPE: return kj::strTree("UInt8");
case schema::Type::Body::UINT16_TYPE: return kj::strTree("UInt16");
case schema::Type::Body::UINT32_TYPE: return kj::strTree("UInt32");
case schema::Type::Body::UINT64_TYPE: return kj::strTree("UInt64");
case schema::Type::Body::FLOAT32_TYPE: return kj::strTree("Float32");
case schema::Type::Body::FLOAT64_TYPE: return kj::strTree("Float64");
case schema::Type::Body::TEXT_TYPE: return kj::strTree("Text");
case schema::Type::Body::DATA_TYPE: return kj::strTree("Data");
case schema::Type::Body::LIST_TYPE:
return kj::strTree("List(", genType(body.getListType(), scope), ")");
case schema::Type::Body::ENUM_TYPE:
return nodeName(scope.getDependency(body.getEnumType()), scope);
case schema::Type::Body::STRUCT_TYPE:
return nodeName(scope.getDependency(body.getStructType()), scope);
case schema::Type::Body::INTERFACE_TYPE:
return nodeName(scope.getDependency(body.getInterfaceType()), scope);
case schema::Type::Body::OBJECT_TYPE: return kj::strTree("Object");
} }
return kj::strTree();
}
int typeSizeBits(schema::Type::Reader type) { kj::StringTree genType(schema::Type::Reader type, Schema scope) {
switch (type.getBody().which()) { auto body = type.getBody();
case schema::Type::Body::VOID_TYPE: return 0; switch (body.which()) {
case schema::Type::Body::BOOL_TYPE: return 1; case schema::Type::Body::VOID_TYPE: return kj::strTree("Void");
case schema::Type::Body::INT8_TYPE: return 8; case schema::Type::Body::BOOL_TYPE: return kj::strTree("Bool");
case schema::Type::Body::INT16_TYPE: return 16; case schema::Type::Body::INT8_TYPE: return kj::strTree("Int8");
case schema::Type::Body::INT32_TYPE: return 32; case schema::Type::Body::INT16_TYPE: return kj::strTree("Int16");
case schema::Type::Body::INT64_TYPE: return 64; case schema::Type::Body::INT32_TYPE: return kj::strTree("Int32");
case schema::Type::Body::UINT8_TYPE: return 8; case schema::Type::Body::INT64_TYPE: return kj::strTree("Int64");
case schema::Type::Body::UINT16_TYPE: return 16; case schema::Type::Body::UINT8_TYPE: return kj::strTree("UInt8");
case schema::Type::Body::UINT32_TYPE: return 32; case schema::Type::Body::UINT16_TYPE: return kj::strTree("UInt16");
case schema::Type::Body::UINT64_TYPE: return 64; case schema::Type::Body::UINT32_TYPE: return kj::strTree("UInt32");
case schema::Type::Body::FLOAT32_TYPE: return 32; case schema::Type::Body::UINT64_TYPE: return kj::strTree("UInt64");
case schema::Type::Body::FLOAT64_TYPE: return 64; case schema::Type::Body::FLOAT32_TYPE: return kj::strTree("Float32");
case schema::Type::Body::TEXT_TYPE: return -1; case schema::Type::Body::FLOAT64_TYPE: return kj::strTree("Float64");
case schema::Type::Body::DATA_TYPE: return -1; case schema::Type::Body::TEXT_TYPE: return kj::strTree("Text");
case schema::Type::Body::LIST_TYPE: return -1; case schema::Type::Body::DATA_TYPE: return kj::strTree("Data");
case schema::Type::Body::ENUM_TYPE: return 16; case schema::Type::Body::LIST_TYPE:
case schema::Type::Body::STRUCT_TYPE: return -1; return kj::strTree("List(", genType(body.getListType(), scope), ")");
case schema::Type::Body::INTERFACE_TYPE: return -1; case schema::Type::Body::ENUM_TYPE:
case schema::Type::Body::OBJECT_TYPE: return -1; return nodeName(scope.getDependency(body.getEnumType()), scope);
case schema::Type::Body::STRUCT_TYPE:
return nodeName(scope.getDependency(body.getStructType()), scope);
case schema::Type::Body::INTERFACE_TYPE:
return nodeName(scope.getDependency(body.getInterfaceType()), scope);
case schema::Type::Body::OBJECT_TYPE: return kj::strTree("Object");
}
return kj::strTree();
} }
return 0;
}
bool isEmptyValue(schema::Value::Reader value) { int typeSizeBits(schema::Type::Reader type) {
auto body = value.getBody(); switch (type.getBody().which()) {
switch (body.which()) { case schema::Type::Body::VOID_TYPE: return 0;
case schema::Value::Body::VOID_VALUE: return true; case schema::Type::Body::BOOL_TYPE: return 1;
case schema::Value::Body::BOOL_VALUE: return body.getBoolValue() == false; case schema::Type::Body::INT8_TYPE: return 8;
case schema::Value::Body::INT8_VALUE: return body.getInt8Value() == 0; case schema::Type::Body::INT16_TYPE: return 16;
case schema::Value::Body::INT16_VALUE: return body.getInt16Value() == 0; case schema::Type::Body::INT32_TYPE: return 32;
case schema::Value::Body::INT32_VALUE: return body.getInt32Value() == 0; case schema::Type::Body::INT64_TYPE: return 64;
case schema::Value::Body::INT64_VALUE: return body.getInt64Value() == 0; case schema::Type::Body::UINT8_TYPE: return 8;
case schema::Value::Body::UINT8_VALUE: return body.getUint8Value() == 0; case schema::Type::Body::UINT16_TYPE: return 16;
case schema::Value::Body::UINT16_VALUE: return body.getUint16Value() == 0; case schema::Type::Body::UINT32_TYPE: return 32;
case schema::Value::Body::UINT32_VALUE: return body.getUint32Value() == 0; case schema::Type::Body::UINT64_TYPE: return 64;
case schema::Value::Body::UINT64_VALUE: return body.getUint64Value() == 0; case schema::Type::Body::FLOAT32_TYPE: return 32;
case schema::Value::Body::FLOAT32_VALUE: return body.getFloat32Value() == 0; case schema::Type::Body::FLOAT64_TYPE: return 64;
case schema::Value::Body::FLOAT64_VALUE: return body.getFloat64Value() == 0; case schema::Type::Body::TEXT_TYPE: return -1;
case schema::Value::Body::TEXT_VALUE: return !body.hasTextValue(); case schema::Type::Body::DATA_TYPE: return -1;
case schema::Value::Body::DATA_VALUE: return !body.hasDataValue(); case schema::Type::Body::LIST_TYPE: return -1;
case schema::Value::Body::LIST_VALUE: return !body.hasListValue(); case schema::Type::Body::ENUM_TYPE: return 16;
case schema::Value::Body::ENUM_VALUE: return body.getEnumValue() == 0; case schema::Type::Body::STRUCT_TYPE: return -1;
case schema::Value::Body::STRUCT_VALUE: return !body.hasStructValue(); case schema::Type::Body::INTERFACE_TYPE: return -1;
case schema::Value::Body::INTERFACE_VALUE: return true; case schema::Type::Body::OBJECT_TYPE: return -1;
case schema::Value::Body::OBJECT_VALUE: return true; }
return 0;
} }
return true;
}
kj::StringTree genValue(schema::Type::Reader type, schema::Value::Reader value, Schema scope) { bool isEmptyValue(schema::Value::Reader value) {
auto body = value.getBody(); auto body = value.getBody();
switch (body.which()) { switch (body.which()) {
case schema::Value::Body::VOID_VALUE: return kj::strTree("void"); case schema::Value::Body::VOID_VALUE: return true;
case schema::Value::Body::BOOL_VALUE: case schema::Value::Body::BOOL_VALUE: return body.getBoolValue() == false;
return kj::strTree(body.getBoolValue() ? "true" : "false"); case schema::Value::Body::INT8_VALUE: return body.getInt8Value() == 0;
case schema::Value::Body::INT8_VALUE: return kj::strTree((int)body.getInt8Value()); case schema::Value::Body::INT16_VALUE: return body.getInt16Value() == 0;
case schema::Value::Body::INT16_VALUE: return kj::strTree(body.getInt16Value()); case schema::Value::Body::INT32_VALUE: return body.getInt32Value() == 0;
case schema::Value::Body::INT32_VALUE: return kj::strTree(body.getInt32Value()); case schema::Value::Body::INT64_VALUE: return body.getInt64Value() == 0;
case schema::Value::Body::INT64_VALUE: return kj::strTree(body.getInt64Value()); case schema::Value::Body::UINT8_VALUE: return body.getUint8Value() == 0;
case schema::Value::Body::UINT8_VALUE: return kj::strTree((uint)body.getUint8Value()); case schema::Value::Body::UINT16_VALUE: return body.getUint16Value() == 0;
case schema::Value::Body::UINT16_VALUE: return kj::strTree(body.getUint16Value()); case schema::Value::Body::UINT32_VALUE: return body.getUint32Value() == 0;
case schema::Value::Body::UINT32_VALUE: return kj::strTree(body.getUint32Value()); case schema::Value::Body::UINT64_VALUE: return body.getUint64Value() == 0;
case schema::Value::Body::UINT64_VALUE: return kj::strTree(body.getUint64Value()); case schema::Value::Body::FLOAT32_VALUE: return body.getFloat32Value() == 0;
case schema::Value::Body::FLOAT32_VALUE: return kj::strTree(body.getFloat32Value()); case schema::Value::Body::FLOAT64_VALUE: return body.getFloat64Value() == 0;
case schema::Value::Body::FLOAT64_VALUE: return kj::strTree(body.getFloat64Value()); case schema::Value::Body::TEXT_VALUE: return !body.hasTextValue();
case schema::Value::Body::TEXT_VALUE: case schema::Value::Body::DATA_VALUE: return !body.hasDataValue();
return kj::strTree(DynamicValue::Reader(body.getTextValue())); case schema::Value::Body::LIST_VALUE: return !body.hasListValue();
case schema::Value::Body::DATA_VALUE: case schema::Value::Body::ENUM_VALUE: return body.getEnumValue() == 0;
return kj::strTree(DynamicValue::Reader(body.getDataValue())); case schema::Value::Body::STRUCT_VALUE: return !body.hasStructValue();
case schema::Value::Body::LIST_VALUE: { case schema::Value::Body::INTERFACE_VALUE: return true;
KJ_REQUIRE(type.getBody().which() == schema::Type::Body::LIST_TYPE, "type/value mismatch"); case schema::Value::Body::OBJECT_VALUE: return true;
auto value = body.getListValue<DynamicList>(
ListSchema::of(type.getBody().getListType(), scope));
return kj::strTree(value);
}
case schema::Value::Body::ENUM_VALUE: {
KJ_REQUIRE(type.getBody().which() == schema::Type::Body::ENUM_TYPE, "type/value mismatch");
auto enumNode = scope.getDependency(type.getBody().getEnumType()).asEnum().getProto();
auto enumType = enumNode.getBody().getEnumNode();
auto enumerants = enumType.getEnumerants();
KJ_REQUIRE(body.getEnumValue() < enumerants.size(),
"Enum value out-of-range.", body.getEnumValue(), enumNode.getDisplayName());
return kj::strTree(enumerants[body.getEnumValue()].getName());
}
case schema::Value::Body::STRUCT_VALUE: {
KJ_REQUIRE(type.getBody().which() == schema::Type::Body::STRUCT_TYPE, "type/value mismatch");
auto value = body.getStructValue<DynamicStruct>(
scope.getDependency(type.getBody().getStructType()).asStruct());
return kj::strTree(value);
}
case schema::Value::Body::INTERFACE_VALUE: {
return kj::strTree("");
}
case schema::Value::Body::OBJECT_VALUE: {
return kj::strTree("");
} }
return true;
} }
return kj::strTree("");
}
kj::StringTree genAnnotation(schema::Annotation::Reader annotation, kj::StringTree genValue(schema::Type::Reader type, schema::Value::Reader value, Schema scope) {
Schema scope, auto body = value.getBody();
const char* prefix = " ", const char* suffix = "") { switch (body.which()) {
auto decl = schemaLoader.get(annotation.getId()); case schema::Value::Body::VOID_VALUE: return kj::strTree("void");
auto body = decl.getProto().getBody(); case schema::Value::Body::BOOL_VALUE:
KJ_REQUIRE(body.which() == schema::Node::Body::ANNOTATION_NODE); return kj::strTree(body.getBoolValue() ? "true" : "false");
auto annDecl = body.getAnnotationNode(); case schema::Value::Body::INT8_VALUE: return kj::strTree((int)body.getInt8Value());
case schema::Value::Body::INT16_VALUE: return kj::strTree(body.getInt16Value());
case schema::Value::Body::INT32_VALUE: return kj::strTree(body.getInt32Value());
case schema::Value::Body::INT64_VALUE: return kj::strTree(body.getInt64Value());
case schema::Value::Body::UINT8_VALUE: return kj::strTree((uint)body.getUint8Value());
case schema::Value::Body::UINT16_VALUE: return kj::strTree(body.getUint16Value());
case schema::Value::Body::UINT32_VALUE: return kj::strTree(body.getUint32Value());
case schema::Value::Body::UINT64_VALUE: return kj::strTree(body.getUint64Value());
case schema::Value::Body::FLOAT32_VALUE: return kj::strTree(body.getFloat32Value());
case schema::Value::Body::FLOAT64_VALUE: return kj::strTree(body.getFloat64Value());
case schema::Value::Body::TEXT_VALUE:
return kj::strTree(DynamicValue::Reader(body.getTextValue()));
case schema::Value::Body::DATA_VALUE:
return kj::strTree(DynamicValue::Reader(body.getDataValue()));
case schema::Value::Body::LIST_VALUE: {
KJ_REQUIRE(type.getBody().which() == schema::Type::Body::LIST_TYPE, "type/value mismatch");
auto value = body.getListValue<DynamicList>(
ListSchema::of(type.getBody().getListType(), scope));
return kj::strTree(value);
}
case schema::Value::Body::ENUM_VALUE: {
KJ_REQUIRE(type.getBody().which() == schema::Type::Body::ENUM_TYPE, "type/value mismatch");
auto enumNode = scope.getDependency(type.getBody().getEnumType()).asEnum().getProto();
auto enumType = enumNode.getBody().getEnumNode();
auto enumerants = enumType.getEnumerants();
KJ_REQUIRE(body.getEnumValue() < enumerants.size(),
"Enum value out-of-range.", body.getEnumValue(), enumNode.getDisplayName());
return kj::strTree(enumerants[body.getEnumValue()].getName());
}
case schema::Value::Body::STRUCT_VALUE: {
KJ_REQUIRE(type.getBody().which() == schema::Type::Body::STRUCT_TYPE,
"type/value mismatch");
auto value = body.getStructValue<DynamicStruct>(
scope.getDependency(type.getBody().getStructType()).asStruct());
return kj::strTree(value);
}
case schema::Value::Body::INTERFACE_VALUE: {
return kj::strTree("");
}
case schema::Value::Body::OBJECT_VALUE: {
return kj::strTree("");
}
}
return kj::strTree("");
}
return kj::strTree(prefix, "$", nodeName(decl, scope), "(", kj::StringTree genAnnotation(schema::Annotation::Reader annotation,
genValue(annDecl.getType(), annotation.getValue(), scope), ")", suffix); Schema scope,
} const char* prefix = " ", const char* suffix = "") {
auto decl = schemaLoader.get(annotation.getId());
auto body = decl.getProto().getBody();
KJ_REQUIRE(body.which() == schema::Node::Body::ANNOTATION_NODE);
auto annDecl = body.getAnnotationNode();
kj::StringTree genAnnotations(List<schema::Annotation>::Reader list, Schema scope) { return kj::strTree(prefix, "$", nodeName(decl, scope), "(",
return kj::strTree(KJ_MAP(list, ann) { return genAnnotation(ann, scope); }); genValue(annDecl.getType(), annotation.getValue(), scope), ")", suffix);
} }
kj::StringTree genAnnotations(Schema schema) {
auto proto = schema.getProto();
return genAnnotations(proto.getAnnotations(), schemaLoader.get(proto.getScopeId()));
}
const char* elementSizeName(schema::ElementSize size) { kj::StringTree genAnnotations(List<schema::Annotation>::Reader list, Schema scope) {
switch (size) { return kj::strTree(KJ_MAP(list, ann) { return genAnnotation(ann, scope); });
case schema::ElementSize::EMPTY: return "void"; }
case schema::ElementSize::BIT: return "1-bit"; kj::StringTree genAnnotations(Schema schema) {
case schema::ElementSize::BYTE: return "8-bit"; auto proto = schema.getProto();
case schema::ElementSize::TWO_BYTES: return "16-bit"; return genAnnotations(proto.getAnnotations(), schemaLoader.get(proto.getScopeId()));
case schema::ElementSize::FOUR_BYTES: return "32-bit";
case schema::ElementSize::EIGHT_BYTES: return "64-bit";
case schema::ElementSize::POINTER: return "pointer";
case schema::ElementSize::INLINE_COMPOSITE: return "inline composite";
} }
return "";
}
kj::StringTree genStructMember(schema::StructNode::Member::Reader member, const char* elementSizeName(schema::ElementSize size) {
Schema scope, Indent indent, int unionTag = -1) { switch (size) {
switch (member.getBody().which()) { case schema::ElementSize::EMPTY: return "void";
case schema::StructNode::Member::Body::FIELD_MEMBER: { case schema::ElementSize::BIT: return "1-bit";
auto field = member.getBody().getFieldMember(); case schema::ElementSize::BYTE: return "8-bit";
int size = typeSizeBits(field.getType()); case schema::ElementSize::TWO_BYTES: return "16-bit";
return kj::strTree( case schema::ElementSize::FOUR_BYTES: return "32-bit";
indent, member.getName(), " @", member.getOrdinal(), case schema::ElementSize::EIGHT_BYTES: return "64-bit";
" :", genType(field.getType(), scope), case schema::ElementSize::POINTER: return "pointer";
isEmptyValue(field.getDefaultValue()) ? kj::strTree("") : case schema::ElementSize::INLINE_COMPOSITE: return "inline composite";
kj::strTree(" = ", genValue(field.getType(), field.getDefaultValue(), scope)),
genAnnotations(member.getAnnotations(), scope),
"; # ", size == -1 ? kj::strTree("ptr[", field.getOffset(), "]")
: kj::strTree("bits[", field.getOffset() * size, ", ",
(field.getOffset() + 1) * size, ")"),
unionTag != -1 ? kj::strTree(", union tag = ", unionTag) : kj::strTree(),
"\n");
}
case schema::StructNode::Member::Body::UNION_MEMBER: {
auto un = member.getBody().getUnionMember();
int i = 0;
return kj::strTree(
indent, member.getName(), " @", member.getOrdinal(),
" union", genAnnotations(member.getAnnotations(), scope),
" { # tag bits[", un.getDiscriminantOffset() * 16, ", ",
un.getDiscriminantOffset() * 16 + 16, ")\n",
KJ_MAP(un.getMembers(), member) {
return genStructMember(member, scope, indent.next(), i++);
},
indent, "}\n");
}
case schema::StructNode::Member::Body::GROUP_MEMBER: {
auto group = member.getBody().getGroupMember();
return kj::strTree(
indent, member.getName(),
" group", genAnnotations(member.getAnnotations(), scope), " {",
unionTag != -1 ? kj::strTree(" # union tag = ", unionTag) : kj::strTree(), "\n",
KJ_MAP(group.getMembers(), member) {
return genStructMember(member, scope, indent.next());
},
indent, "}\n");
} }
return "";
} }
return kj::strTree();
}
kj::StringTree genNestedDecls(Schema schema, Indent indent); kj::StringTree genStructMember(schema::StructNode::Member::Reader member,
Schema scope, Indent indent, int unionTag = -1) {
kj::StringTree genDecl(Schema schema, Text::Reader name, uint64_t scopeId, Indent indent) { switch (member.getBody().which()) {
auto proto = schema.getProto(); case schema::StructNode::Member::Body::FIELD_MEMBER: {
if (proto.getScopeId() != scopeId) { auto field = member.getBody().getFieldMember();
// This appears to be an alias for something declared elsewhere. int size = typeSizeBits(field.getType());
KJ_FAIL_REQUIRE("Aliases not implemented."); return kj::strTree(
indent, member.getName(), " @", member.getOrdinal(),
" :", genType(field.getType(), scope),
isEmptyValue(field.getDefaultValue()) ? kj::strTree("") :
kj::strTree(" = ", genValue(field.getType(), field.getDefaultValue(), scope)),
genAnnotations(member.getAnnotations(), scope),
"; # ", size == -1 ? kj::strTree("ptr[", field.getOffset(), "]")
: kj::strTree("bits[", field.getOffset() * size, ", ",
(field.getOffset() + 1) * size, ")"),
unionTag != -1 ? kj::strTree(", union tag = ", unionTag) : kj::strTree(),
"\n");
}
case schema::StructNode::Member::Body::UNION_MEMBER: {
auto un = member.getBody().getUnionMember();
int i = 0;
return kj::strTree(
indent, member.getName(), " @", member.getOrdinal(),
" union", genAnnotations(member.getAnnotations(), scope),
" { # tag bits[", un.getDiscriminantOffset() * 16, ", ",
un.getDiscriminantOffset() * 16 + 16, ")\n",
KJ_MAP(un.getMembers(), member) {
return genStructMember(member, scope, indent.next(), i++);
},
indent, "}\n");
}
case schema::StructNode::Member::Body::GROUP_MEMBER: {
auto group = member.getBody().getGroupMember();
return kj::strTree(
indent, member.getName(),
" group", genAnnotations(member.getAnnotations(), scope), " {",
unionTag != -1 ? kj::strTree(" # union tag = ", unionTag) : kj::strTree(), "\n",
KJ_MAP(group.getMembers(), member) {
return genStructMember(member, scope, indent.next());
},
indent, "}\n");
}
}
return kj::strTree();
} }
switch (proto.getBody().which()) { kj::StringTree genDecl(Schema schema, Text::Reader name, uint64_t scopeId, Indent indent) {
case schema::Node::Body::FILE_NODE: auto proto = schema.getProto();
KJ_FAIL_REQUIRE("Encountered nested file node."); if (proto.getScopeId() != scopeId) {
break; // This appears to be an alias for something declared elsewhere.
case schema::Node::Body::STRUCT_NODE: { KJ_FAIL_REQUIRE("Aliases not implemented.");
auto body = proto.getBody().getStructNode();
return kj::strTree(
indent, "struct ", name, " @0x", kj::hex(proto.getId()), genAnnotations(schema), " { # ",
body.getDataSectionWordSize() * 8, " bytes, ",
body.getPointerSectionSize(), " ptrs",
body.getPreferredListEncoding() == schema::ElementSize::INLINE_COMPOSITE
? kj::strTree()
: kj::strTree(", packed as ", elementSizeName(body.getPreferredListEncoding())),
"\n",
KJ_MAP(body.getMembers(), member) {
return genStructMember(member, schema, indent.next());
},
genNestedDecls(schema, indent.next()),
indent, "}\n");
}
case schema::Node::Body::ENUM_NODE: {
auto body = proto.getBody().getEnumNode();
uint i = 0;
return kj::strTree(
indent, "enum ", name, " @0x", kj::hex(proto.getId()), genAnnotations(schema), " {\n",
KJ_MAP(body.getEnumerants(), enumerant) {
return kj::strTree(indent.next(), enumerant.getName(), " @", i++,
genAnnotations(enumerant.getAnnotations(), schema), ";\n");
},
genNestedDecls(schema, indent.next()),
indent, "}\n");
} }
case schema::Node::Body::INTERFACE_NODE: {
auto body = proto.getBody().getInterfaceNode(); switch (proto.getBody().which()) {
uint i = 0; case schema::Node::Body::FILE_NODE:
return kj::strTree( KJ_FAIL_REQUIRE("Encountered nested file node.");
indent, "interface ", name, " @0x", kj::hex(proto.getId()), break;
genAnnotations(schema), " {\n", case schema::Node::Body::STRUCT_NODE: {
KJ_MAP(body.getMethods(), method) { auto body = proto.getBody().getStructNode();
int j = 0; return kj::strTree(
return kj::strTree( indent, "struct ", name,
indent.next(), method.getName(), " @", i++, "(", " @0x", kj::hex(proto.getId()), genAnnotations(schema), " { # ",
KJ_MAP(method.getParams(), param) { body.getDataSectionWordSize() * 8, " bytes, ",
bool hasDefault = j >= method.getRequiredParamCount() || body.getPointerSectionSize(), " ptrs",
!isEmptyValue(param.getDefaultValue()); body.getPreferredListEncoding() == schema::ElementSize::INLINE_COMPOSITE
return kj::strTree( ? kj::strTree()
j++ > 0 ? ", " : "", : kj::strTree(", packed as ", elementSizeName(body.getPreferredListEncoding())),
param.getName(), ": ", genType(param.getType(), schema), "\n",
hasDefault KJ_MAP(body.getMembers(), member) {
? kj::strTree(" = ", genValue( return genStructMember(member, schema, indent.next());
param.getType(), param.getDefaultValue(), schema)) },
: kj::strTree(), genNestedDecls(schema, indent.next()),
genAnnotations(param.getAnnotations(), schema)); indent, "}\n");
}, }
") :", genType(method.getReturnType(), schema), case schema::Node::Body::ENUM_NODE: {
genAnnotations(method.getAnnotations(), schema), ";\n"); auto body = proto.getBody().getEnumNode();
}, uint i = 0;
genNestedDecls(schema, indent.next()), return kj::strTree(
indent, "}\n"); indent, "enum ", name, " @0x", kj::hex(proto.getId()), genAnnotations(schema), " {\n",
} KJ_MAP(body.getEnumerants(), enumerant) {
case schema::Node::Body::CONST_NODE: { return kj::strTree(indent.next(), enumerant.getName(), " @", i++,
auto body = proto.getBody().getConstNode(); genAnnotations(enumerant.getAnnotations(), schema), ";\n");
return kj::strTree( },
indent, "const ", name, " @0x", kj::hex(proto.getId()), " :", genNestedDecls(schema, indent.next()),
genType(body.getType(), schema), " = ", indent, "}\n");
genValue(body.getType(), body.getValue(), schema), ";\n"); }
} case schema::Node::Body::INTERFACE_NODE: {
case schema::Node::Body::ANNOTATION_NODE: { auto body = proto.getBody().getInterfaceNode();
auto body = proto.getBody().getAnnotationNode(); uint i = 0;
kj::CappedArray<const char*, 11> targets; return kj::strTree(
uint i = 0; indent, "interface ", name, " @0x", kj::hex(proto.getId()),
if (body.getTargetsFile()) targets[i++] = "file"; genAnnotations(schema), " {\n",
if (body.getTargetsConst()) targets[i++] = "const"; KJ_MAP(body.getMethods(), method) {
if (body.getTargetsEnum()) targets[i++] = "enum"; int j = 0;
if (body.getTargetsEnumerant()) targets[i++] = "enumerant"; return kj::strTree(
if (body.getTargetsStruct()) targets[i++] = "struct"; indent.next(), method.getName(), " @", i++, "(",
if (body.getTargetsField()) targets[i++] = "field"; KJ_MAP(method.getParams(), param) {
if (body.getTargetsUnion()) targets[i++] = "union"; bool hasDefault = j >= method.getRequiredParamCount() ||
if (body.getTargetsInterface()) targets[i++] = "interface"; !isEmptyValue(param.getDefaultValue());
if (body.getTargetsMethod()) targets[i++] = "method"; return kj::strTree(
if (body.getTargetsParam()) targets[i++] = "param"; j++ > 0 ? ", " : "",
if (body.getTargetsAnnotation()) targets[i++] = "annotation"; param.getName(), ": ", genType(param.getType(), schema),
if (i == targets.size()) { hasDefault
targets[0] = "*"; ? kj::strTree(" = ", genValue(
targets.setSize(1); param.getType(), param.getDefaultValue(), schema))
} else { : kj::strTree(),
targets.setSize(i); genAnnotations(param.getAnnotations(), schema));
},
") :", genType(method.getReturnType(), schema),
genAnnotations(method.getAnnotations(), schema), ";\n");
},
genNestedDecls(schema, indent.next()),
indent, "}\n");
}
case schema::Node::Body::CONST_NODE: {
auto body = proto.getBody().getConstNode();
return kj::strTree(
indent, "const ", name, " @0x", kj::hex(proto.getId()), " :",
genType(body.getType(), schema), " = ",
genValue(body.getType(), body.getValue(), schema), ";\n");
}
case schema::Node::Body::ANNOTATION_NODE: {
auto body = proto.getBody().getAnnotationNode();
kj::CappedArray<const char*, 11> targets;
uint i = 0;
if (body.getTargetsFile()) targets[i++] = "file";
if (body.getTargetsConst()) targets[i++] = "const";
if (body.getTargetsEnum()) targets[i++] = "enum";
if (body.getTargetsEnumerant()) targets[i++] = "enumerant";
if (body.getTargetsStruct()) targets[i++] = "struct";
if (body.getTargetsField()) targets[i++] = "field";
if (body.getTargetsUnion()) targets[i++] = "union";
if (body.getTargetsInterface()) targets[i++] = "interface";
if (body.getTargetsMethod()) targets[i++] = "method";
if (body.getTargetsParam()) targets[i++] = "param";
if (body.getTargetsAnnotation()) targets[i++] = "annotation";
if (i == targets.size()) {
targets[0] = "*";
targets.setSize(1);
} else {
targets.setSize(i);
}
return kj::strTree(
indent, "annotation ", name, " @0x", kj::hex(proto.getId()),
" (", strArray(targets, ", "), ") :",
genType(body.getType(), schema), genAnnotations(schema), ";\n");
} }
return kj::strTree(
indent, "annotation ", name, " @0x", kj::hex(proto.getId()),
" (", strArray(targets, ", "), ") :",
genType(body.getType(), schema), genAnnotations(schema), ";\n");
} }
return kj::strTree();
} }
return kj::strTree(); kj::StringTree genNestedDecls(Schema schema, Indent indent) {
} uint64_t id = schema.getProto().getId();
return kj::strTree(KJ_MAP(schema.getProto().getNestedNodes(), nested) {
return genDecl(schemaLoader.get(nested.getId()), nested.getName(), id, indent);
});
}
kj::StringTree genNestedDecls(Schema schema, Indent indent) { kj::StringTree genFile(Schema file) {
uint64_t id = schema.getProto().getId(); auto proto = file.getProto();
return kj::strTree(KJ_MAP(schema.getProto().getNestedNodes(), nested) { auto body = proto.getBody();
return genDecl(schemaLoader.get(nested.getId()), nested.getName(), id, indent); KJ_REQUIRE(body.which() == schema::Node::Body::FILE_NODE, "Expected a file node.",
}); (uint)body.which());
}
return kj::strTree(
"# ", proto.getDisplayName(), "\n",
"@0x", kj::hex(proto.getId()), ";\n",
KJ_MAP(proto.getAnnotations(), ann) { return genAnnotation(ann, file, "", ";\n"); },
genNestedDecls(file, Indent(0)));
}
kj::StringTree genFile(Schema file) { kj::MainBuilder::Validity run() {
auto proto = file.getProto(); ReaderOptions options;
auto body = proto.getBody(); options.traversalLimitInWords = 1 << 30; // Don't limit.
KJ_REQUIRE(body.which() == schema::Node::Body::FILE_NODE, "Expected a file node.", StreamFdMessageReader reader(STDIN_FILENO, options);
(uint)body.which()); auto request = reader.getRoot<schema::CodeGeneratorRequest>();
return kj::strTree(
"# ", proto.getDisplayName(), "\n",
"@0x", kj::hex(proto.getId()), ";\n",
KJ_MAP(proto.getAnnotations(), ann) { return genAnnotation(ann, file, "", ";\n"); },
genNestedDecls(file, Indent(0)));
}
int main(int argc, char* argv[]) { for (auto node: request.getNodes()) {
ReaderOptions options; schemaLoader.load(node);
options.traversalLimitInWords = 1 << 30; // Don't limit. }
StreamFdMessageReader reader(STDIN_FILENO, options);
auto request = reader.getRoot<schema::CodeGeneratorRequest>();
for (auto node: request.getNodes()) { kj::FdOutputStream rawOut(STDOUT_FILENO);
schemaLoader.load(node); kj::BufferedOutputStreamWrapper out(rawOut);
}
kj::FdOutputStream rawOut(STDOUT_FILENO); for (auto fileId: request.getRequestedFiles()) {
kj::BufferedOutputStreamWrapper out(rawOut); genFile(schemaLoader.get(fileId)).visit(
[&](kj::ArrayPtr<const char> text) {
out.write(text.begin(), text.size());
});
}
for (auto fileId: request.getRequestedFiles()) { return true;
genFile(schemaLoader.get(fileId)).visit(
[&](kj::ArrayPtr<const char> text) {
out.write(text.begin(), text.size());
});
} }
};
return 0;
}
} // namespace } // namespace
} // namespace capnp } // namespace capnp
int main(int argc, char* argv[]) { KJ_MAIN(capnp::CapnpcCapnpMain);
return capnp::main(argc, argv);
}
...@@ -350,6 +350,11 @@ public: ...@@ -350,6 +350,11 @@ public:
template <typename Iterator> template <typename Iterator>
void addAll(Iterator start, Iterator end); void addAll(Iterator start, Iterator end);
void removeLast() {
KJ_IREQUIRE(pos > ptr, "No elements present to remove.");
kj::dtor(*--pos);
}
Array<T> finish() { Array<T> finish() {
// We could safely remove this check if we assume that the disposer implementation doesn't // We could safely remove this check if we assume that the disposer implementation doesn't
// need to know the original capacity, as is thes case with HeapArrayDisposer since it uses // need to know the original capacity, as is thes case with HeapArrayDisposer since it uses
......
...@@ -87,6 +87,10 @@ public: ...@@ -87,6 +87,10 @@ public:
addAll(container.begin(), container.end()); addAll(container.begin(), container.end());
} }
inline void removeLast() {
builder.removeLast();
}
private: private:
ArrayBuilder<T> builder; ArrayBuilder<T> builder;
......
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