Commit 0c7c610c authored by Kenton Varda's avatar Kenton Varda

More WIP.

parent 1dcb66b1
......@@ -59,52 +59,46 @@ static constexpr const char* FIELD_SIZE_NAMES[] = {
"VOID", "BIT", "BYTE", "TWO_BYTES", "FOUR_BYTES", "EIGHT_BYTES", "POINTER", "INLINE_COMPOSITE"
};
void enumerateDeps(schema::Type::Reader type, std::set<uint64_t>& deps) {
switch (type.getBody().which()) {
case schema::Type::Body::STRUCT_TYPE:
deps.insert(type.getBody().getStructType());
void enumerateDeps(schema2::Type::Reader type, std::set<uint64_t>& deps) {
switch (type.which()) {
case schema2::Type::STRUCT:
deps.insert(type.getStruct());
break;
case schema::Type::Body::ENUM_TYPE:
deps.insert(type.getBody().getEnumType());
case schema2::Type::ENUM:
deps.insert(type.getEnum());
break;
case schema::Type::Body::INTERFACE_TYPE:
deps.insert(type.getBody().getInterfaceType());
case schema2::Type::INTERFACE:
deps.insert(type.getInterface());
break;
case schema::Type::Body::LIST_TYPE:
enumerateDeps(type.getBody().getListType(), deps);
case schema2::Type::LIST:
enumerateDeps(type.getList(), deps);
break;
default:
break;
}
}
void enumerateDeps(schema::StructNode::Member::Reader member, std::set<uint64_t>& deps) {
switch (member.getBody().which()) {
case schema::StructNode::Member::Body::FIELD_MEMBER:
enumerateDeps(member.getBody().getFieldMember().getType(), deps);
break;
case schema::StructNode::Member::Body::UNION_MEMBER:
for (auto subMember: member.getBody().getUnionMember().getMembers()) {
enumerateDeps(subMember, deps);
}
break;
case schema::StructNode::Member::Body::GROUP_MEMBER:
for (auto subMember: member.getBody().getGroupMember().getMembers()) {
enumerateDeps(subMember, deps);
void enumerateDeps(schema2::Node::Reader node, std::set<uint64_t>& deps) {
switch (node.which()) {
case schema2::Node::STRUCT: {
auto structNode = node.getStruct();
for (auto field: structNode.getFields()) {
switch (field.which()) {
case schema2::Field::REGULAR:
enumerateDeps(field.getRegular().getType(), deps);
break;
case schema2::Field::GROUP:
deps.insert(field.getGroup());
break;
}
}
break;
}
}
void enumerateDeps(schema::Node::Reader node, std::set<uint64_t>& deps) {
switch (node.getBody().which()) {
case schema::Node::Body::STRUCT_NODE:
for (auto member: node.getBody().getStructNode().getMembers()) {
enumerateDeps(member, deps);
if (structNode.getIsGroup()) {
deps.insert(node.getScopeId());
}
break;
case schema::Node::Body::INTERFACE_NODE:
for (auto method: node.getBody().getInterfaceNode().getMethods()) {
}
case schema2::Node::INTERFACE:
for (auto method: node.getInterface()) {
for (auto param: method.getParams()) {
enumerateDeps(param.getType(), deps);
}
......@@ -119,92 +113,15 @@ void enumerateDeps(schema::Node::Reader node, std::set<uint64_t>& deps) {
struct OrderByName {
template <typename T>
inline bool operator()(const T& a, const T& b) const {
return a.member.getProto().getName() < b.member.getProto().getName();
}
};
template <typename MemberList>
void makeMemberInfoTable(uint parent, MemberList&& members,
kj::Vector<capnp::_::RawSchema::MemberInfo>& info);
void makeSubMemberInfoTable(const StructSchema::Member& member,
kj::Vector<capnp::_::RawSchema::MemberInfo>& info) {
switch (member.getProto().getBody().which()) {
case schema::StructNode::Member::Body::FIELD_MEMBER:
break;
case schema::StructNode::Member::Body::UNION_MEMBER:
// Only create a sub-table if the union is named.
if (member.getProto().getName().size() > 0) {
makeMemberInfoTable(1 + member.getProto().getOrdinal(),
member.asUnion().getMembers(), info);
}
break;
case schema::StructNode::Member::Body::GROUP_MEMBER:
makeMemberInfoTable(1 + member.getProto().getOrdinal(), member.asGroup().getMembers(), info);
break;
return a.getProto().getName() < b.getProto().getName();
}
}
void makeSubMemberInfoTable(const EnumSchema::Enumerant& member,
kj::Vector<capnp::_::RawSchema::MemberInfo>& info) {}
void makeSubMemberInfoTable(const InterfaceSchema::Method& member,
kj::Vector<capnp::_::RawSchema::MemberInfo>& info) {}
template <typename Member>
struct MemberAndIndex {
Member member;
uint index;
MemberAndIndex(Member member): member(member), index(member.getIndex()) {}
MemberAndIndex(Member member, uint index): member(member), index(index) {}
};
void enumerateScope(const StructSchema::MemberList& members,
kj::Vector<MemberAndIndex<StructSchema::Member>>& vec,
uint offset = 0) {
// Given a member list, flatten all members of the scope into one vector. This basically means
// copying all the members to the vector, except that unnamed unions are flattened, with their
// members' indexes being offset by the size of the parent scope.
for (auto member: members) {
vec.add(member, member.getIndex() + offset);
if (member.getProto().getName().size() == 0) {
// Flatten unnamed union.
enumerateScope(member.asUnion().getMembers(), vec, offset + members.size());
}
}
}
void enumerateScope(const EnumSchema::EnumerantList& members,
kj::Vector<MemberAndIndex<EnumSchema::Enumerant>>& vec) {
for (auto member: members) {
vec.add(member);
}
}
void enumerateScope(const InterfaceSchema::MethodList& members,
kj::Vector<MemberAndIndex<InterfaceSchema::Method>>& vec) {
for (auto member: members) {
vec.add(member);
}
}
template <typename MemberList>
void makeMemberInfoTable(uint parent, MemberList&& members,
kj::Vector<capnp::_::RawSchema::MemberInfo>& info) {
kj::Vector<MemberAndIndex<decltype(members[0])>> sorted(members.size());
enumerateScope(members, sorted);
kj::Array<uint> makeMembersByName(MemberList&& members) {
auto sorted = KJ_MAP(members, member) { return member; };
std::sort(sorted.begin(), sorted.end(), OrderByName());
for (auto& member: sorted) {
info.add(capnp::_::RawSchema::MemberInfo {
kj::implicitCast<uint16_t>(parent),
kj::implicitCast<uint16_t>(member.index)
});
}
for (auto member: members) {
makeSubMemberInfoTable(member, info);
}
return KJ_MAP(sorted, member) { return member.getIndex(); };
}
kj::StringPtr baseName(kj::StringPtr path) {
......@@ -242,7 +159,7 @@ private:
usedImports.insert(node.getId());
for (auto annotation: node.getAnnotations()) {
if (annotation.getId() == NAMESPACE_ANNOTATION_ID) {
return kj::strTree(" ::", annotation.getValue().getBody().getTextValue());
return kj::strTree(" ::", annotation.getValue().getText());
}
}
return kj::strTree(" ");
......@@ -284,36 +201,36 @@ private:
return kj::mv(result);
}
kj::StringTree typeName(schema::Type::Reader type) {
switch (type.getBody().which()) {
case schema::Type::Body::VOID_TYPE: return kj::strTree(" ::capnp::Void");
case schema::Type::Body::BOOL_TYPE: return kj::strTree("bool");
case schema::Type::Body::INT8_TYPE: return kj::strTree(" ::int8_t");
case schema::Type::Body::INT16_TYPE: return kj::strTree(" ::int16_t");
case schema::Type::Body::INT32_TYPE: return kj::strTree(" ::int32_t");
case schema::Type::Body::INT64_TYPE: return kj::strTree(" ::int64_t");
case schema::Type::Body::UINT8_TYPE: return kj::strTree(" ::uint8_t");
case schema::Type::Body::UINT16_TYPE: return kj::strTree(" ::uint16_t");
case schema::Type::Body::UINT32_TYPE: return kj::strTree(" ::uint32_t");
case schema::Type::Body::UINT64_TYPE: return kj::strTree(" ::uint64_t");
case schema::Type::Body::FLOAT32_TYPE: return kj::strTree("float");
case schema::Type::Body::FLOAT64_TYPE: return kj::strTree("double");
case schema::Type::Body::TEXT_TYPE: return kj::strTree(" ::capnp::Text");
case schema::Type::Body::DATA_TYPE: return kj::strTree(" ::capnp::Data");
case schema::Type::Body::ENUM_TYPE:
return cppFullName(schemaLoader.get(type.getBody().getEnumType()));
case schema::Type::Body::STRUCT_TYPE:
return cppFullName(schemaLoader.get(type.getBody().getStructType()));
case schema::Type::Body::INTERFACE_TYPE:
return cppFullName(schemaLoader.get(type.getBody().getInterfaceType()));
case schema::Type::Body::LIST_TYPE:
return kj::strTree(" ::capnp::List<", typeName(type.getBody().getListType()), ">");
case schema::Type::Body::OBJECT_TYPE:
kj::StringTree typeName(schema2::Type::Reader type) {
switch (type.which()) {
case schema2::Type::VOID: return kj::strTree(" ::capnp::Void");
case schema2::Type::BOOL: return kj::strTree("bool");
case schema2::Type::INT8: return kj::strTree(" ::int8_t");
case schema2::Type::INT16: return kj::strTree(" ::int16_t");
case schema2::Type::INT32: return kj::strTree(" ::int32_t");
case schema2::Type::INT64: return kj::strTree(" ::int64_t");
case schema2::Type::UINT8: return kj::strTree(" ::uint8_t");
case schema2::Type::UINT16: return kj::strTree(" ::uint16_t");
case schema2::Type::UINT32: return kj::strTree(" ::uint32_t");
case schema2::Type::UINT64: return kj::strTree(" ::uint64_t");
case schema2::Type::FLOAT32: return kj::strTree("float");
case schema2::Type::FLOAT64: return kj::strTree("double");
case schema2::Type::TEXT: return kj::strTree(" ::capnp::Text");
case schema2::Type::DATA: return kj::strTree(" ::capnp::Data");
case schema2::Type::ENUM:
return cppFullName(schemaLoader.get(type.getEnum()));
case schema2::Type::STRUCT:
return cppFullName(schemaLoader.get(type.getStruct()));
case schema2::Type::INTERFACE:
return cppFullName(schemaLoader.get(type.getInterface()));
case schema2::Type::LIST:
return kj::strTree(" ::capnp::List<", typeName(type.getList()), ">");
case schema2::Type::OBJECT:
// Not used.
return kj::strTree();
}
......@@ -329,29 +246,19 @@ private:
DiscriminantChecks makeDiscriminantChecks(kj::StringPtr scope,
kj::StringPtr memberName,
StructSchema::Union containingUnion) {
auto unionProto = containingUnion.getProto();
kj::StringPtr unionScope;
kj::String ownUnionScope;
if (unionProto.getName().size() > 0) {
ownUnionScope = kj::str(toTitleCase(unionProto.getName()), "::");
unionScope = ownUnionScope;
} else {
// Anonymous union.
unionScope = scope;
}
auto discrimOffset = unionProto.getBody().getUnionMember().getDiscriminantOffset();
StructSchema containingStruct) {
auto discrimOffset = containingStruct.getProto().getStruct().getDiscriminantOffset();
kj::String upperCase = toUpperCase(memberName);
return DiscriminantChecks {
kj::str(
" KJ_IREQUIRE(which() == ", unionScope, upperCase, ",\n"
" KJ_IREQUIRE(which() == ", scope, upperCase, ",\n"
" \"Must check which() before get()ing a union member.\");\n"),
kj::str(
" _builder.setDataField<", unionScope, "Which>(\n"
" _builder.setDataField<", scope, "Which>(\n"
" ", discrimOffset, " * ::capnp::ELEMENTS, ",
unionScope, upperCase, ");\n")
scope, upperCase, ");\n")
};
}
......@@ -372,31 +279,71 @@ private:
OBJECT
};
FieldText makeFieldText(kj::StringPtr scope, StructSchema::Field member) {
auto proto = member.getProto();
auto field = proto.getBody().getFieldMember();
FieldText makeFieldText(kj::StringPtr scope, StructSchema::Field field) {
auto proto = field.getProto();
kj::String titleCase = toTitleCase(proto.getName());
DiscriminantChecks unionDiscrim;
if (proto.hasDiscriminantValue()) {
unionDiscrim = makeDiscriminantChecks(scope, proto.getName(), field.getContainingStruct());
}
switch (proto.which()) {
case schema2::Field::REGULAR:
// Continue below.
break;
case schema2::Field::GROUP:
return FieldText {
kj::strTree(
" inline ", titleCase, "::Reader get", titleCase, "() const;\n"
"\n"),
kj::strTree(
" inline ", titleCase, "::Builder get", titleCase, "();\n"
" inline ", titleCase, "::Builder init", titleCase, "();\n"
"\n"),
kj::strTree(
"inline ", scope, titleCase, "::Reader ", scope, "Reader::get", titleCase, "() const {\n",
unionDiscrim.check,
" return ", scope, titleCase, "::Reader(_reader);\n"
"}\n"
"inline ", scope, titleCase, "::Builder ", scope, "Builder::get", titleCase, "() {\n",
unionDiscrim.check,
" return ", scope, titleCase, "::Builder(_builder);\n"
"}\n"
"inline ", scope, titleCase, "::Builder ", scope, "Builder::init", titleCase, "() {\n",
unionDiscrim.set,
// TODO(soon): Zero out fields.
" return ", scope, titleCase, "::Builder(_builder);\n"
"}\n")
};
}
auto regularField = proto.getRegular();
FieldKind kind;
kj::String ownedType;
kj::String type = typeName(field.getType()).flatten();
kj::String type = typeName(regularField.getType()).flatten();
kj::StringPtr setterDefault; // only for void
kj::String defaultMask; // primitives only
size_t defaultOffset = 0; // pointers only: offset of the default value within the schema.
size_t defaultSize = 0; // blobs only: byte size of the default value.
auto typeBody = field.getType().getBody();
auto defaultBody = field.getDefaultValue().getBody();
auto typeBody = regularField.getType();
auto defaultBody = regularField.getDefaultValue();
switch (typeBody.which()) {
case schema::Type::Body::VOID_TYPE:
case schema2::Type::VOID:
kind = FieldKind::PRIMITIVE;
setterDefault = " = ::capnp::Void::VOID";
break;
#define HANDLE_PRIMITIVE(discrim, typeName, defaultName, suffix) \
case schema::Type::Body::discrim##_TYPE: \
case schema2::Type::discrim: \
kind = FieldKind::PRIMITIVE; \
if (defaultBody.get##defaultName##Value() != 0) { \
defaultMask = kj::str(defaultBody.get##defaultName##Value(), #suffix); \
if (defaultBody.get##defaultName() != 0) { \
defaultMask = kj::str(defaultBody.get##defaultName(), #suffix); \
} \
break;
......@@ -411,69 +358,69 @@ private:
HANDLE_PRIMITIVE(UINT64, ::uint64_t, Uint64, ull);
#undef HANDLE_PRIMITIVE
case schema::Type::Body::FLOAT32_TYPE:
case schema2::Type::FLOAT32:
kind = FieldKind::PRIMITIVE;
if (defaultBody.getFloat32Value() != 0) {
if (defaultBody.getFloat32() != 0) {
uint32_t mask;
float value = defaultBody.getFloat32Value();
float value = defaultBody.getFloat32();
static_assert(sizeof(mask) == sizeof(value), "bug");
memcpy(&mask, &value, sizeof(mask));
defaultMask = kj::str(mask, "u");
}
break;
case schema::Type::Body::FLOAT64_TYPE:
case schema2::Type::FLOAT64:
kind = FieldKind::PRIMITIVE;
if (defaultBody.getFloat64Value() != 0) {
if (defaultBody.getFloat64() != 0) {
uint64_t mask;
double value = defaultBody.getFloat64Value();
double value = defaultBody.getFloat64();
static_assert(sizeof(mask) == sizeof(value), "bug");
memcpy(&mask, &value, sizeof(mask));
defaultMask = kj::str(mask, "ull");
}
break;
case schema::Type::Body::TEXT_TYPE:
case schema2::Type::TEXT:
kind = FieldKind::BLOB;
if (defaultBody.hasTextValue()) {
defaultOffset = member.getDefaultValueSchemaOffset();
defaultSize = defaultBody.getTextValue().size();
if (defaultBody.hasText()) {
defaultOffset = field.getDefaultValueSchemaOffset();
defaultSize = defaultBody.getText().size();
}
break;
case schema::Type::Body::DATA_TYPE:
case schema2::Type::DATA:
kind = FieldKind::BLOB;
if (defaultBody.hasDataValue()) {
defaultOffset = member.getDefaultValueSchemaOffset();
defaultSize = defaultBody.getDataValue().size();
if (defaultBody.hasData()) {
defaultOffset = field.getDefaultValueSchemaOffset();
defaultSize = defaultBody.getData().size();
}
break;
case schema::Type::Body::ENUM_TYPE:
case schema2::Type::ENUM:
kind = FieldKind::PRIMITIVE;
if (defaultBody.getEnumValue() != 0) {
defaultMask = kj::str(defaultBody.getEnumValue(), "u");
if (defaultBody.getEnum() != 0) {
defaultMask = kj::str(defaultBody.getEnum(), "u");
}
break;
case schema::Type::Body::STRUCT_TYPE:
case schema2::Type::STRUCT:
kind = FieldKind::STRUCT;
if (defaultBody.hasStructValue()) {
defaultOffset = member.getDefaultValueSchemaOffset();
if (defaultBody.hasStruct()) {
defaultOffset = field.getDefaultValueSchemaOffset();
}
break;
case schema::Type::Body::LIST_TYPE:
case schema2::Type::LIST:
kind = FieldKind::LIST;
if (defaultBody.hasListValue()) {
defaultOffset = member.getDefaultValueSchemaOffset();
if (defaultBody.hasList()) {
defaultOffset = field.getDefaultValueSchemaOffset();
}
break;
case schema::Type::Body::INTERFACE_TYPE:
case schema2::Type::INTERFACE:
kind = FieldKind::INTERFACE;
break;
case schema::Type::Body::OBJECT_TYPE:
case schema2::Type::OBJECT:
kind = FieldKind::OBJECT;
if (defaultBody.hasObjectValue()) {
defaultOffset = member.getDefaultValueSchemaOffset();
if (defaultBody.hasObject()) {
defaultOffset = field.getDefaultValueSchemaOffset();
}
break;
}
......@@ -483,14 +430,7 @@ private:
defaultMaskParam = kj::str(", ", defaultMask);
}
kj::String titleCase = toTitleCase(proto.getName());
DiscriminantChecks unionDiscrim;
KJ_IF_MAYBE(u, member.getContainingUnion()) {
unionDiscrim = makeDiscriminantChecks(scope, proto.getName(), *u);
}
uint offset = field.getOffset();
uint offset = regularField.getOffset();
if (kind == FieldKind::PRIMITIVE) {
return FieldText {
......@@ -635,7 +575,7 @@ private:
} else {
// Blob, struct, or list. These have only minor differences.
uint64_t typeId = member.getContainingStruct().getProto().getId();
uint64_t typeId = field.getContainingStruct().getProto().getId();
kj::String defaultParam = defaultOffset == 0 ? kj::str() : kj::str(
",\n ::capnp::schemas::s_", kj::hex(typeId), ".encodedNode + ", defaultOffset,
defaultSize == 0 ? kj::strTree() : kj::strTree(", ", defaultSize));
......@@ -644,38 +584,38 @@ private:
bool isStructList = false;
if (kind == FieldKind::LIST) {
bool primitiveElement = false;
switch (typeBody.getListType().getBody().which()) {
case schema::Type::Body::VOID_TYPE:
case schema::Type::Body::BOOL_TYPE:
case schema::Type::Body::INT8_TYPE:
case schema::Type::Body::INT16_TYPE:
case schema::Type::Body::INT32_TYPE:
case schema::Type::Body::INT64_TYPE:
case schema::Type::Body::UINT8_TYPE:
case schema::Type::Body::UINT16_TYPE:
case schema::Type::Body::UINT32_TYPE:
case schema::Type::Body::UINT64_TYPE:
case schema::Type::Body::FLOAT32_TYPE:
case schema::Type::Body::FLOAT64_TYPE:
case schema::Type::Body::ENUM_TYPE:
switch (typeBody.getList().which()) {
case schema2::Type::VOID:
case schema2::Type::BOOL:
case schema2::Type::INT8:
case schema2::Type::INT16:
case schema2::Type::INT32:
case schema2::Type::INT64:
case schema2::Type::UINT8:
case schema2::Type::UINT16:
case schema2::Type::UINT32:
case schema2::Type::UINT64:
case schema2::Type::FLOAT32:
case schema2::Type::FLOAT64:
case schema2::Type::ENUM:
primitiveElement = true;
break;
case schema::Type::Body::TEXT_TYPE:
case schema::Type::Body::DATA_TYPE:
case schema::Type::Body::LIST_TYPE:
case schema::Type::Body::INTERFACE_TYPE:
case schema::Type::Body::OBJECT_TYPE:
case schema2::Type::TEXT:
case schema2::Type::DATA:
case schema2::Type::LIST:
case schema2::Type::INTERFACE:
case schema2::Type::OBJECT:
primitiveElement = false;
break;
case schema::Type::Body::STRUCT_TYPE:
case schema2::Type::STRUCT:
isStructList = true;
primitiveElement = false;
break;
}
elementReaderType = kj::str(
typeName(typeBody.getListType()),
typeName(typeBody.getList()),
primitiveElement ? "" : "::Reader");
}
......@@ -766,7 +706,7 @@ private:
// -----------------------------------------------------------------
kj::StringTree makeReaderDef(kj::StringPtr fullName, kj::StringPtr unqualifiedParentType,
kj::StringPtr stringifier, kj::StringTree&& methodDecls) {
bool isUnion, kj::Array<kj::StringTree>&& methodDecls) {
return kj::strTree(
"class ", fullName, "::Reader {\n"
"public:\n"
......@@ -779,6 +719,7 @@ private:
" return _reader.totalSize() / ::capnp::WORDS;\n"
" }\n"
"\n",
isUnion ? kj::strTree(" inline Which which() const;\n") : kj::strTree(),
kj::mv(methodDecls),
"private:\n"
" ::capnp::_::StructReader _reader;\n"
......@@ -792,16 +733,15 @@ private:
" friend class ::capnp::Orphanage;\n"
" friend ::kj::StringTree KJ_STRINGIFY(", fullName, "::Reader reader);\n"
"};\n"
"\n",
stringifier.size() > 0 ? kj::strTree(
"inline ::kj::StringTree KJ_STRINGIFY(", fullName, "::Reader reader) {\n"
" return ::capnp::_::", stringifier, "<", fullName, ">(reader._reader);\n"
"}\n"
"\n") : kj::strTree());
"\n"
"inline ::kj::StringTree KJ_STRINGIFY(", fullName, "::Reader reader) {\n"
" return ::capnp::_::structString<", fullName, ">(reader._reader);\n"
"}\n"
"\n");
}
kj::StringTree makeBuilderDef(kj::StringPtr fullName, kj::StringPtr unqualifiedParentType,
kj::StringPtr stringifier, kj::StringTree&& methodDecls) {
bool isUnion, kj::Array<kj::StringTree>&& methodDecls) {
return kj::strTree(
"class ", fullName, "::Builder {\n"
"public:\n"
......@@ -814,6 +754,7 @@ private:
"\n"
" inline size_t totalSizeInWords() { return asReader().totalSizeInWords(); }\n"
"\n",
isUnion ? kj::strTree(" inline Which which();\n") : kj::strTree(),
kj::mv(methodDecls),
"private:\n"
" ::capnp::_::StructBuilder _builder;\n"
......@@ -822,235 +763,11 @@ private:
" friend class ::capnp::Orphanage;\n"
" friend ::kj::StringTree KJ_STRINGIFY(", fullName, "::Builder builder);\n"
"};\n"
"\n",
stringifier.size() > 0 ? kj::strTree(
"inline ::kj::StringTree KJ_STRINGIFY(", fullName, "::Builder builder) {\n"
" return ::capnp::_::", stringifier, "<", fullName, ">(builder._builder.asReader());\n"
"}\n"
"\n") : kj::strTree());
}
// -----------------------------------------------------------------
struct MembersText {
kj::StringTree innerTypeDecls;
kj::StringTree innerTypeDefs;
kj::StringTree innerTypeReaderBuilderDefs;
kj::StringTree readerMethodDecls;
kj::StringTree builderMethodDecls;
kj::StringTree inlineMethodDefs;
kj::StringTree capnpPrivateDecls;
kj::StringTree capnpPrivateDefs;
};
MembersText makeMemberText(kj::StringPtr namespace_, kj::StringPtr containingType,
StructSchema::Member member) {
auto proto = member.getProto();
switch (proto.getBody().which()) {
case schema::StructNode::Member::Body::FIELD_MEMBER: {
auto fieldText = makeFieldText(kj::str(containingType, "::"), member.asField());
return MembersText {
kj::strTree(),
kj::strTree(),
kj::strTree(),
kj::mv(fieldText.readerMethodDecls),
kj::mv(fieldText.builderMethodDecls),
kj::mv(fieldText.inlineMethodDefs),
kj::strTree(),
kj::strTree(),
};
}
case schema::StructNode::Member::Body::UNION_MEMBER: {
auto subMembers = member.asUnion().getMembers();
auto unionName = proto.getName();
uint discrimOffset = proto.getBody().getUnionMember().getDiscriminantOffset();
auto whichEnumDef = kj::strTree(
" enum Which: uint16_t {\n",
KJ_MAP(subMembers, subMember) {
return kj::strTree(
" ", toUpperCase(subMember.getProto().getName()), ",\n");
},
" };\n");
if (unionName.size() == 0) {
// Anonymous union.
auto subText = makeMembersText(namespace_, containingType, subMembers);
return MembersText {
kj::strTree(kj::mv(whichEnumDef), kj::mv(subText.innerTypeDecls)),
kj::mv(subText.innerTypeDefs),
kj::mv(subText.innerTypeReaderBuilderDefs),
kj::strTree(
" inline Which which() const;\n",
kj::mv(subText.readerMethodDecls)),
kj::strTree(
" inline Which which();\n",
kj::mv(subText.builderMethodDecls)),
kj::strTree(
"inline ", containingType, "::Which ", containingType, "::Reader::which() const {\n"
" return _reader.getDataField<Which>(", discrimOffset, " * ::capnp::ELEMENTS);\n"
"}\n"
"inline ", containingType, "::Which ", containingType, "::Builder::which() {\n"
" return _builder.getDataField<Which>(", discrimOffset, " * ::capnp::ELEMENTS);\n"
"}\n"
"\n",
kj::mv(subText.inlineMethodDefs)),
kj::mv(subText.capnpPrivateDecls),
kj::mv(subText.capnpPrivateDefs),
};
} else {
// Named union.
auto titleCase = toTitleCase(unionName);
auto fullName = kj::str(containingType, "::", titleCase);
auto subText = makeMembersText(namespace_, fullName, subMembers);
return MembersText {
kj::strTree(
" struct ", titleCase, ";\n"),
kj::strTree(
"struct ", fullName, " {\n"
" ", titleCase, "() = delete;\n"
" class Reader;\n"
" class Builder;\n"
"\n",
kj::mv(whichEnumDef),
kj::mv(subText.innerTypeDecls),
"};\n"
"\n",
kj::mv(subText.innerTypeDefs)),
kj::strTree(
makeReaderDef(fullName, titleCase, "unionString", kj::strTree(
" inline Which which() const;\n",
kj::mv(subText.readerMethodDecls))),
makeBuilderDef(fullName, titleCase, "unionString", kj::strTree(
" inline Which which();\n",
kj::mv(subText.builderMethodDecls))),
kj::mv(subText.innerTypeReaderBuilderDefs)),
kj::strTree(
" inline ", titleCase, "::Reader get", titleCase, "() const;\n"),
kj::strTree(
" inline ", titleCase, "::Builder get", titleCase, "();\n"),
kj::strTree(
"inline ", fullName, "::Reader ", containingType, "::Reader::get", titleCase, "() const {\n"
" return ", fullName, "::Reader(_reader);\n"
"}\n"
"inline ", fullName, "::Builder ", containingType, "::Builder::get", titleCase, "() {\n"
" return ", fullName, "::Builder(_builder);\n"
"}\n"
"inline ", fullName, "::Which ", fullName, "::Reader::which() const {\n"
" return _reader.getDataField<Which>(", discrimOffset, " * ::capnp::ELEMENTS);\n"
"}\n"
"inline ", fullName, "::Which ", fullName, "::Builder::which() {\n"
" return _builder.getDataField<Which>(", discrimOffset, " * ::capnp::ELEMENTS);\n"
"}\n"
"\n",
kj::mv(subText.inlineMethodDefs)),
kj::strTree(
"CAPNP_DECLARE_UNION(\n"
" ", namespace_, "::", fullName, ",\n"
" ", namespace_, "::", containingType, ", ", member.getIndex(), ");\n",
kj::mv(subText.capnpPrivateDecls)),
kj::strTree(
"CAPNP_DEFINE_UNION(\n"
" ", namespace_, "::", fullName, ");\n",
kj::mv(subText.capnpPrivateDefs)),
};
}
}
case schema::StructNode::Member::Body::GROUP_MEMBER: {
auto titleCase = toTitleCase(proto.getName());
auto fullName = kj::str(containingType, "::", titleCase);
auto subText = makeMembersText(namespace_, fullName, member.asGroup().getMembers());
DiscriminantChecks unionDiscrim;
KJ_IF_MAYBE(u, member.getContainingUnion()) {
unionDiscrim = makeDiscriminantChecks(
kj::str(containingType, "::"), proto.getName(), *u);
}
return MembersText {
kj::strTree(
" struct ", titleCase, ";\n"),
kj::strTree(
"struct ", containingType, "::", titleCase, " {\n"
" ", titleCase, "() = delete;\n"
"\n",
" class Reader;\n"
" class Builder;\n",
kj::mv(subText.innerTypeDecls),
"};\n"
"\n",
kj::mv(subText.innerTypeDefs)),
kj::strTree(
makeReaderDef(fullName, titleCase, "",
kj::mv(subText.readerMethodDecls)),
makeBuilderDef(fullName, titleCase, "",
kj::mv(subText.builderMethodDecls)),
kj::mv(subText.innerTypeReaderBuilderDefs)),
kj::strTree(
" inline ", titleCase, "::Reader get", titleCase, "() const;\n"),
kj::strTree(
" inline ", titleCase, "::Builder get", titleCase, "();\n"
" inline ", titleCase, "::Builder init", titleCase, "();\n"),
kj::strTree(
"inline ", fullName, "::Reader ", containingType, "::Reader::get", titleCase, "() const {\n",
unionDiscrim.check,
" return ", fullName, "::Reader(_reader);\n"
"}\n"
"inline ", fullName, "::Builder ", containingType, "::Builder::get", titleCase, "() {\n",
unionDiscrim.check,
" return ", fullName, "::Builder(_builder);\n"
"}\n"
// TODO(soon): This should really zero out the existing group. Maybe unions should
// support zeroing out the whole union?
"inline ", fullName, "::Builder ", containingType, "::Builder::init", titleCase, "() {\n",
unionDiscrim.set,
" return ", fullName, "::Builder(_builder);\n"
"}\n",
kj::mv(subText.inlineMethodDefs)),
kj::mv(subText.capnpPrivateDecls),
kj::mv(subText.capnpPrivateDefs),
};
}
}
KJ_UNREACHABLE;
}
MembersText makeMembersText(kj::StringPtr namespace_, kj::StringPtr containingType,
StructSchema::MemberList members) {
auto memberTexts = KJ_MAP(members, member) {
return makeMemberText(namespace_, containingType, member);
};
return MembersText {
kj::strTree(KJ_MAP(memberTexts, m) { return kj::mv(m.innerTypeDecls); }),
kj::strTree(KJ_MAP(memberTexts, m) { return kj::mv(m.innerTypeDefs); }),
kj::strTree(KJ_MAP(memberTexts, m) { return kj::mv(m.innerTypeReaderBuilderDefs); }),
kj::strTree(KJ_MAP(memberTexts, m) { return kj::mv(m.readerMethodDecls); }),
kj::strTree(KJ_MAP(memberTexts, m) { return kj::mv(m.builderMethodDecls); }),
kj::strTree(KJ_MAP(memberTexts, m) { return kj::mv(m.inlineMethodDefs); }),
kj::strTree(KJ_MAP(memberTexts, m) { return kj::mv(m.capnpPrivateDecls); }),
kj::strTree(KJ_MAP(memberTexts, m) { return kj::mv(m.capnpPrivateDefs); }),
};
"\n"
"inline ::kj::StringTree KJ_STRINGIFY(", fullName, "::Builder builder) {\n"
" return ::capnp::_::structString<", fullName, ">(builder._builder.asReader());\n"
"}\n"
"\n");
}
// -----------------------------------------------------------------
......@@ -1071,14 +788,27 @@ private:
auto proto = schema.getProto();
auto fullName = kj::str(scope, name);
auto subScope = kj::str(fullName, "::");
auto nestedTexts = KJ_MAP(proto.getNestedNodes(), nested) {
return makeNodeText(namespace_, subScope, nested.getName(), schemaLoader.get(nested.getId()));
};
auto hexId = kj::hex(proto.getId());
kj::ArrayPtr<const word> rawSchema = schema.asUncheckedMessage();
// Compute nested nodes, including groups.
kj::Vector<NodeText> nestedTexts(proto.getNestedNodes().size());
for (auto nested: proto.getNestedNodes()) {
nestedTexts.add(makeNodeText(
namespace_, subScope, nested.getName(), schemaLoader.get(nested.getId())));
};
if (proto.which() == schema2::Node::STRUCT) {
for (auto field: proto.getStruct().getFields()) {
if (field.which() == schema2::Field::GROUP) {
nestedTexts.add(makeNodeText(
namespace_, subScope, toTitleCase(field.getName()),
schemaLoader.get(field.getGroup())));
}
}
}
// Convert the encoded schema to a literal byte array.
kj::ArrayPtr<const word> rawSchema = schema.asUncheckedMessage();
auto schemaLiteral = kj::StringTree(KJ_MAP(rawSchema, w) {
const byte* bytes = reinterpret_cast<const byte*>(&w);
......@@ -1094,16 +824,16 @@ private:
std::set<uint64_t> deps;
enumerateDeps(proto, deps);
kj::Vector<capnp::_::RawSchema::MemberInfo> memberInfos;
switch (proto.getBody().which()) {
case schema::Node::Body::STRUCT_NODE:
makeMemberInfoTable(0, schema.asStruct().getMembers(), memberInfos);
kj::Array<uint> membersByName;
switch (proto.which()) {
case schema2::Node::STRUCT:
membersByName = makeMembersByName(schema.asStruct().getFields());
break;
case schema::Node::Body::ENUM_NODE:
makeMemberInfoTable(0, schema.asEnum().getEnumerants(), memberInfos);
case schema2::Node::ENUM:
membersByName = makeMembersByName(schema.asEnum().getEnumerants());
break;
case schema::Node::Body::INTERFACE_NODE:
makeMemberInfoTable(0, schema.asInterface().getMethods(), memberInfos);
case schema2::Node::INTERFACE:
membersByName = makeMembersByName(schema.asInterface().getMethods());
break;
default:
break;
......@@ -1119,51 +849,66 @@ private:
},
"};\n"
"static const ::capnp::_::RawSchema::MemberInfo m_", hexId, "[] = {\n",
KJ_MAP(memberInfos, info) {
return kj::strTree(" { ", info.scopeOrdinal, ", ", info.index, " },\n");
},
kj::StringTree(KJ_MAP(membersByName, index) { return kj::strTree(index); }, ", "),
"};\n"
"const ::capnp::_::RawSchema s_", hexId, " = {\n"
" 0x", hexId, ", b_", hexId, ".words, ", rawSchema.size(), ", d_", hexId, ", m_", hexId, ",\n"
" ", deps.size(), ", ", memberInfos.size(), ", nullptr, nullptr\n"
" ", deps.size(), ", ", membersByName.size(), ", nullptr, nullptr\n"
"};\n");
switch (proto.getBody().which()) {
case schema::Node::Body::FILE_NODE:
switch (proto.which()) {
case schema2::Node::FILE:
KJ_FAIL_REQUIRE("This method shouldn't be called on file nodes.");
case schema::Node::Body::STRUCT_NODE: {
auto membersText = makeMembersText(namespace_, fullName, schema.asStruct().getMembers());
case schema2::Node::STRUCT: {
auto fieldTexts =
KJ_MAP(schema.asStruct().getFields(), f) { return makeFieldText(subScope, f); };
auto structNode = proto.getBody().getStructNode();
auto structNode = proto.getStruct();
uint discrimOffset = structNode.getDiscriminantOffset();
return NodeText {
kj::strTree(
" struct ", name, ";\n"),
kj::strTree(
"struct ", scope, name, " {\n",
"struct ", fullName, " {\n",
" ", name, "() = delete;\n"
"\n"
" class Reader;\n"
" class Builder;\n",
kj::mv(membersText.innerTypeDecls),
structNode.getDiscriminantCount() == 0 ? kj::strTree() : kj::strTree(
" enum Which: uint16_t {\n",
KJ_MAP(structNode.getFields(), f) {
if (f.hasDiscriminantValue()) {
return kj::strTree(" ", toUpperCase(f.getName()), ",\n");
} else {
return kj::strTree();
}
},
" };\n"),
KJ_MAP(nestedTexts, n) { return kj::mv(n.outerTypeDecl); },
"};\n"
"\n",
kj::mv(membersText.innerTypeDefs),
KJ_MAP(nestedTexts, n) { return kj::mv(n.outerTypeDef); }),
kj::strTree(
makeReaderDef(fullName, name, "structString",
kj::mv(membersText.readerMethodDecls)),
makeBuilderDef(fullName, name, "structString",
kj::mv(membersText.builderMethodDecls)),
kj::mv(membersText.innerTypeReaderBuilderDefs),
makeReaderDef(fullName, name, structNode.getDiscriminantCount() != 0,
KJ_MAP(fieldTexts, f) { return kj::mv(f.readerMethodDecls); }),
makeBuilderDef(fullName, name, structNode.getDiscriminantCount() != 0,
KJ_MAP(fieldTexts, f) { return kj::mv(f.builderMethodDecls); }),
KJ_MAP(nestedTexts, n) { return kj::mv(n.readerBuilderDefs); }),
kj::strTree(
kj::mv(membersText.inlineMethodDefs),
structNode.getDiscriminantCount() == 0 ? kj::strTree() : kj::strTree(
"inline ", fullName, "::Which ", fullName, "::Reader::which() const {\n"
" return _reader.getDataField<Which>(", discrimOffset, " * ::capnp::ELEMENTS);\n"
"}\n"
"inline ", fullName, "::Which ", fullName, "::Builder::which() {\n"
" return _builder.getDataField<Which>(", discrimOffset, " * ::capnp::ELEMENTS);\n"
"}\n"
"\n"),
KJ_MAP(fieldTexts, f) { return kj::mv(f.inlineMethodDefs); },
KJ_MAP(nestedTexts, n) { return kj::mv(n.inlineMethodDefs); }),
kj::strTree(
......@@ -1181,18 +926,16 @@ private:
structNode.getPointerSectionSize(), ", ",
FIELD_SIZE_NAMES[static_cast<uint>(structNode.getPreferredListEncoding())],
");\n",
kj::mv(membersText.capnpPrivateDecls),
KJ_MAP(nestedTexts, n) { return kj::mv(n.capnpPrivateDecls); }),
kj::strTree(
"CAPNP_DEFINE_STRUCT(\n"
" ", namespace_, "::", fullName, ");\n",
kj::mv(membersText.capnpPrivateDefs),
KJ_MAP(nestedTexts, n) { return kj::mv(n.capnpPrivateDefs); }),
};
}
case schema::Node::Body::ENUM_NODE: {
case schema2::Node::ENUM: {
auto enumerants = schema.asEnum().getEnumerants();
return NodeText {
......@@ -1227,7 +970,7 @@ private:
};
}
case schema::Node::Body::INTERFACE_NODE: {
case schema2::Node::INTERFACE: {
return NodeText {
kj::strTree(),
kj::strTree(),
......@@ -1246,7 +989,7 @@ private:
};
}
case schema::Node::Body::CONST_NODE: {
case schema2::Node::CONST: {
return NodeText {
kj::strTree(),
kj::strTree(),
......@@ -1261,7 +1004,7 @@ private:
};
}
case schema::Node::Body::ANNOTATION_NODE: {
case schema2::Node::ANNOTATION: {
return NodeText {
kj::strTree(),
kj::strTree(),
......@@ -1287,7 +1030,8 @@ private:
kj::StringTree source;
};
FileText makeFileText(Schema schema) {
FileText makeFileText(Schema schema,
schema2::CodeGeneratorRequest::RequestedFile::Reader request) {
usedImports.clear();
auto node = schema.getProto();
......@@ -1298,7 +1042,7 @@ private:
for (auto annotation: node.getAnnotations()) {
if (annotation.getId() == NAMESPACE_ANNOTATION_ID) {
kj::StringPtr ns = annotation.getValue().getBody().getTextValue();
kj::StringPtr ns = annotation.getValue().getText();
kj::StringPtr ns2 = ns;
namespacePrefix = kj::str("::", ns);
......@@ -1327,7 +1071,7 @@ private:
kj::String separator = kj::str("// ", kj::repeat('=', 87), "\n");
kj::Vector<kj::StringPtr> includes;
for (auto import: node.getBody().getFileNode().getImports()) {
for (auto import: request.getImports()) {
if (usedImports.count(import.getId()) > 0) {
includes.add(import.getName());
}
......@@ -1430,7 +1174,7 @@ private:
ReaderOptions options;
options.traversalLimitInWords = 1 << 30; // Don't limit.
StreamFdMessageReader reader(STDIN_FILENO, options);
auto request = reader.getRoot<schema::CodeGeneratorRequest>();
auto request = reader.getRoot<schema2::CodeGeneratorRequest>();
for (auto node: request.getNodes()) {
schemaLoader.load(node);
......@@ -1439,9 +1183,9 @@ private:
kj::FdOutputStream rawOut(STDOUT_FILENO);
kj::BufferedOutputStreamWrapper out(rawOut);
for (auto fileId: request.getRequestedFiles()) {
auto schema = schemaLoader.get(fileId);
auto fileText = makeFileText(schema);
for (auto requestedFile: request.getRequestedFiles()) {
auto schema = schemaLoader.get(requestedFile.getId());
auto fileText = makeFileText(schema, requestedFile);
writeFile(kj::str(schema.getProto().getDisplayName(), ".h"), fileText.header);
writeFile(kj::str(schema.getProto().getDisplayName(), ".c++"), fileText.source);
......
......@@ -810,10 +810,7 @@ public:
}
schema2::Field::Builder fieldBuilder = member.getSchema();
fieldBuilder.setName(member.decl.getName().getValue());
fieldBuilder.getOrdinal().setExplicit(entry.first);
fieldBuilder.setCodeOrder(member.codeOrder);
switch (member.decl.getBody().which()) {
case Declaration::Body::FIELD_DECL: {
......@@ -891,7 +888,7 @@ public:
// OK, we should have built all the members. Now go through and make sure the discriminant
// offsets have been copied over to the schemas and annotations have been applied.
root.setDiscriminantOffsetInSchema();
root.finishGroup();
for (auto member: allMembers) {
kj::StringPtr targetsFlagName;
switch (member->decl.getBody().which()) {
......@@ -900,13 +897,12 @@ public:
break;
case Declaration::Body::UNION_DECL:
member->setDiscriminantOffsetInSchema();
member->finishGroup();
targetsFlagName = "targetsUnion";
break;
case Declaration::Body::GROUP_DECL:
member->setDiscriminantOffsetInSchema(); // in case it contains an unnamed union
member->node.setId(generateGroupId(member->parent->node.getId(), member->index));
member->finishGroup();
targetsFlagName = "targetsGroup";
break;
......@@ -1026,6 +1022,8 @@ private:
if (isInUnion) {
builder.setDiscriminantValue(parent->unionDiscriminantCount++);
}
builder.setName(decl.getName().getValue());
builder.setCodeOrder(codeOrder);
schema = builder;
return builder;
}
......@@ -1039,20 +1037,28 @@ private:
auto structNode = node.getStruct();
if (!structNode.hasFields()) {
getSchema(); // Make sure field exists in parent once the first child is added.
if (parent != nullptr) {
getSchema(); // Make sure field exists in parent once the first child is added.
}
return structNode.initFields(childCount)[childInitializedCount++];
} else {
return structNode.getFields()[childInitializedCount++];
}
}
void setDiscriminantOffsetInSchema() {
void finishGroup() {
if (unionScope != nullptr) {
unionScope->addDiscriminant(); // if it hasn't happened already
auto structNode = node.getStruct();
structNode.setDiscriminantCount(unionDiscriminantCount);
structNode.setDiscriminantOffset(KJ_ASSERT_NONNULL(unionScope->discriminantOffset));
}
if (parent != nullptr) {
uint64_t groupId = generateGroupId(parent->node.getId(), index);
node.setId(groupId);
getSchema().setGroup(groupId);
}
}
};
......@@ -1064,9 +1070,7 @@ private:
// All members, including ones that don't have ordinals.
void traverseUnion(List<Declaration>::Reader members, MemberInfo& parent,
StructLayout::Union& layout) {
uint codeOrder = 0;
StructLayout::Union& layout, uint& codeOrder) {
if (members.size() < 2) {
errorReporter.addErrorOn(parent.decl, "Union must have at least two members.");
}
......@@ -1145,8 +1149,11 @@ private:
case Declaration::Body::UNION_DECL: {
StructLayout::Union& unionLayout = arena.allocate<StructLayout::Union>(layout);
uint independentSubCodeOrder = 0;
uint* subCodeOrder = &independentSubCodeOrder;
if (member.getName().getValue() == "") {
memberInfo = &parent;
subCodeOrder = &codeOrder;
} else {
parent.childCount++;
memberInfo = &arena.allocate<MemberInfo>(
......@@ -1156,7 +1163,7 @@ private:
allMembers.add(memberInfo);
}
memberInfo->unionScope = &unionLayout;
traverseUnion(member.getNestedDecls(), *memberInfo, unionLayout);
traverseUnion(member.getNestedDecls(), *memberInfo, unionLayout, *subCodeOrder);
if (member.getId().which() == Declaration::Id::ORDINAL) {
ordinal = member.getId().getOrdinal().getValue();
}
......@@ -1517,8 +1524,17 @@ void NodeTranslator::compileValue(ValueExpression::Reader source, schema2::Type:
schema2::Value::Builder target, bool isBootstrap) {
#warning "temporary hack for schema transition"
switch (type.which()) {
case schema2::Type::TEXT:
target.setText(source.getBody().getString());
break;
case schema2::Type::UINT16:
target.setUint16(source.getBody().getPositiveInt());
break;
default:
KJ_FAIL_ASSERT("Need to compile value type:", (uint)type.which());
KJ_FAIL_ASSERT("Need to compile value type:", (uint)type.which(),
wipNode.getReader().getDisplayName());
}
#if 0
......
......@@ -240,7 +240,8 @@ inline kj::StringTree structString(StructReader reader) {
template <typename T>
inline kj::StringTree unionString(StructReader reader) {
return unionString(reader, rawSchema<UnionParentType<T>>(), unionMemberIndex<T>());
#warning "remove this"
return kj::strTree();
}
} // namespace _ (private)
......
......@@ -71,7 +71,8 @@ public:
TryGetResult tryGet(uint64_t typeId) const;
kj::Array<Schema> getAllLoaded() const;
void requireStructSize(uint64_t id, uint dataWordCount, uint pointerCount);
void requireStructSize(uint64_t id, uint dataWordCount, uint pointerCount,
schema2::ElementSize preferredListEncoding);
// Require any struct nodes loaded with this ID -- in the past and in the future -- to have at
// least the given sizes. Struct nodes that don't comply will simply be rewritten to comply.
// This is used to ensure that parents of group nodes have at least the size of the group node,
......@@ -86,6 +87,7 @@ private:
struct RequiredSize {
uint16_t dataWordCount;
uint16_t pointerCount;
schema2::ElementSize preferredListEncoding;
};
std::unordered_map<uint64_t, RequiredSize> structSizeRequirements;
......@@ -103,13 +105,15 @@ private:
// (but at least can't cause memory corruption).
kj::ArrayPtr<word> rewriteStructNodeWithSizes(
schema2::Node::Reader node, uint dataWordCount, uint pointerCount);
schema2::Node::Reader node, uint dataWordCount, uint pointerCount,
schema2::ElementSize preferredListEncoding);
// Make a copy of the given node (which must be a struct node) and set its sizes to be the max
// of what it said already and the given sizes.
// If the encoded node does not meet the given struct size requirements, make a new copy that
// does.
void applyStructSizeRequirement(_::RawSchema* raw, uint dataWordCount, uint pointerCount);
void applyStructSizeRequirement(_::RawSchema* raw, uint dataWordCount, uint pointerCount,
schema2::ElementSize preferredListEncoding);
};
// =======================================================================================
......@@ -340,7 +344,8 @@ private:
// Require that the group's scope has at least the same size as the group, so that anyone
// constructing an instance of the outer scope can safely read/write the group.
loader.requireStructSize(scopeId, structNode.getDataSectionWordSize(),
structNode.getPointerSectionSize());
structNode.getPointerSectionSize(),
structNode.getPreferredListEncoding());
// Require that the parent type is a struct.
validateTypeId(scopeId, schema2::Node::STRUCT);
......@@ -1131,7 +1136,8 @@ _::RawSchema* SchemaLoader::Impl::loadNative(const _::RawSchema* nativeSchema) {
auto reqIter = structSizeRequirements.find(nativeSchema->id);
if (reqIter != structSizeRequirements.end()) {
applyStructSizeRequirement(result, reqIter->second.dataWordCount,
reqIter->second.pointerCount);
reqIter->second.pointerCount,
reqIter->second.preferredListEncoding);
}
} else {
// The existing schema is newer.
......@@ -1200,14 +1206,21 @@ kj::Array<Schema> SchemaLoader::Impl::getAllLoaded() const {
return result;
}
void SchemaLoader::Impl::requireStructSize(uint64_t id, uint dataWordCount, uint pointerCount) {
void SchemaLoader::Impl::requireStructSize(uint64_t id, uint dataWordCount, uint pointerCount,
schema2::ElementSize preferredListEncoding) {
auto& slot = structSizeRequirements[id];
slot.dataWordCount = kj::max(slot.dataWordCount, dataWordCount);
slot.pointerCount = kj::max(slot.pointerCount, pointerCount);
if (slot.dataWordCount + slot.pointerCount >= 2) {
slot.preferredListEncoding = schema2::ElementSize::INLINE_COMPOSITE;
} else {
slot.preferredListEncoding = kj::max(slot.preferredListEncoding, preferredListEncoding);
}
auto iter = schemas.find(id);
if (iter != schemas.end()) {
applyStructSizeRequirement(iter->second, dataWordCount, pointerCount);
applyStructSizeRequirement(iter->second, dataWordCount, pointerCount, preferredListEncoding);
}
}
......@@ -1227,9 +1240,11 @@ kj::ArrayPtr<word> SchemaLoader::Impl::makeUncheckedNodeEnforcingSizeRequirement
auto requirement = iter->second;
auto structNode = node.getStruct();
if (structNode.getDataSectionWordSize() < requirement.dataWordCount ||
structNode.getPointerSectionSize() < requirement.pointerCount) {
structNode.getPointerSectionSize() < requirement.pointerCount ||
structNode.getPreferredListEncoding() < requirement.preferredListEncoding) {
return rewriteStructNodeWithSizes(node, requirement.dataWordCount,
requirement.pointerCount);
requirement.pointerCount,
requirement.preferredListEncoding);
}
}
}
......@@ -1238,7 +1253,8 @@ kj::ArrayPtr<word> SchemaLoader::Impl::makeUncheckedNodeEnforcingSizeRequirement
}
kj::ArrayPtr<word> SchemaLoader::Impl::rewriteStructNodeWithSizes(
schema2::Node::Reader node, uint dataWordCount, uint pointerCount) {
schema2::Node::Reader node, uint dataWordCount, uint pointerCount,
schema2::ElementSize preferredListEncoding) {
MallocMessageBuilder builder;
builder.setRoot(node);
......@@ -1247,18 +1263,28 @@ kj::ArrayPtr<word> SchemaLoader::Impl::rewriteStructNodeWithSizes(
newStruct.setDataSectionWordSize(kj::max(newStruct.getDataSectionWordSize(), dataWordCount));
newStruct.setPointerSectionSize(kj::max(newStruct.getPointerSectionSize(), pointerCount));
if (newStruct.getDataSectionWordSize() + newStruct.getPointerSectionSize() >= 2) {
newStruct.setPreferredListEncoding(schema2::ElementSize::INLINE_COMPOSITE);
} else {
newStruct.setPreferredListEncoding(
kj::max(newStruct.getPreferredListEncoding(), preferredListEncoding));
}
return makeUncheckedNode(root);
}
void SchemaLoader::Impl::applyStructSizeRequirement(
_::RawSchema* raw, uint dataWordCount, uint pointerCount) {
_::RawSchema* raw, uint dataWordCount, uint pointerCount,
schema2::ElementSize preferredListEncoding) {
auto node = readMessageUnchecked<schema2::Node>(raw->encodedNode);
auto structNode = node.getStruct();
if (structNode.getDataSectionWordSize() < dataWordCount ||
structNode.getPointerSectionSize() < pointerCount) {
structNode.getPointerSectionSize() < pointerCount ||
structNode.getPreferredListEncoding() < preferredListEncoding) {
// Sizes need to be increased. Must rewrite.
kj::ArrayPtr<word> words = rewriteStructNodeWithSizes(node, dataWordCount, pointerCount);
kj::ArrayPtr<word> words = rewriteStructNodeWithSizes(
node, dataWordCount, pointerCount, preferredListEncoding);
// We don't need to re-validate the node because we know this change could not possibly have
// invalidated it. Just remake the unchecked message.
......
......@@ -154,8 +154,6 @@ private:
friend class Schema;
friend kj::StringTree _::structString(
_::StructReader reader, const _::RawSchema& schema);
friend kj::StringTree _::unionString(
_::StructReader reader, const _::RawSchema& schema, uint fieldIndex);
};
class StructSchema::Field {
......
......@@ -42,7 +42,7 @@ struct Node {
# If you want a shorter version of `displayName` (just naming this node, without its surrounding
# scope), chop off this many characters from the beginning of `displayName`.
scopeId @3 :Id = 0;
scopeId @3 :Id;
# ID of the lexical parent node. Typically, the scope node will have a NestedNode pointing back
# at this node, but robust code should avoid relying on this (and, in fact, group nodes are not
# listed in the outer struct's nestedNodes, since they are listed in the fields). `scopeId` is
......@@ -105,7 +105,8 @@ struct Node {
# `isGroup` = true.
discriminantOffset @12 :UInt32;
# If `isUnion` is true, this is the offset of the union discriminant, in multiples of 16 bits.
# If `discriminantCount` is non-zero, this is the offset of the union discriminant, in
# multiples of 16 bits.
fields @13 :List(Field);
# Fields defined within this scope (either the struct's top-level fields, or the fields of
......
......@@ -99,21 +99,19 @@ private:
}
};
schema::Type::Body::Which whichMemberType(const StructSchema::Member& member) {
auto body = member.getProto().getBody();
switch (body.which()) {
case schema::StructNode::Member::Body::UNION_MEMBER:
return schema::Type::Body::VOID_TYPE;
case schema::StructNode::Member::Body::GROUP_MEMBER:
return schema::Type::Body::STRUCT_TYPE;
case schema::StructNode::Member::Body::FIELD_MEMBER:
return body.getFieldMember().getType().getBody().which();
static schema2::Type::Which whichFieldType(const StructSchema::Field& field) {
auto proto = field.getProto();
switch (proto.which()) {
case schema2::Field::REGULAR:
return proto.getRegular().getType().which();
case schema2::Field::GROUP:
return schema2::Type::STRUCT;
}
KJ_UNREACHABLE;
}
static kj::StringTree print(const DynamicValue::Reader& value,
schema::Type::Body::Which which, Indent indent,
schema2::Type::Which which, Indent indent,
PrintMode mode) {
switch (value.getType()) {
case DynamicValue::UNKNOWN:
......@@ -127,7 +125,7 @@ static kj::StringTree print(const DynamicValue::Reader& value,
case DynamicValue::UINT:
return kj::strTree(value.as<uint64_t>());
case DynamicValue::FLOAT:
if (which == schema::Type::Body::FLOAT32_TYPE) {
if (which == schema2::Type::FLOAT32) {
return kj::strTree(value.as<float>());
} else {
return kj::strTree(value.as<double>());
......@@ -192,40 +190,31 @@ static kj::StringTree print(const DynamicValue::Reader& value,
}
case DynamicValue::STRUCT: {
auto structValue = value.as<DynamicStruct>();
auto memberSchemas = structValue.getSchema().getMembers();
kj::Vector<kj::StringTree> printedMembers(memberSchemas.size());
for (auto member: memberSchemas) {
if (structValue.has(member)) {
auto name = member.getProto().getName();
if (name.size() == 0) {
// Unnamed union. Just print the content.
printedMembers.add(kj::strTree(
print(structValue.get(member), whichMemberType(member), indent.next(), BARE)));
} else {
printedMembers.add(kj::strTree(
name, " = ",
print(structValue.get(member), whichMemberType(member), indent.next(), PREFIXED)));
}
auto unionFields = structValue.getSchema().getUnionFields();
auto nonUnionFields = structValue.getSchema().getNonUnionFields();
kj::Vector<kj::StringTree> printedFields(nonUnionFields.size() + (unionFields.size() != 0));
KJ_IF_MAYBE(field, structValue.which()) {
if (structValue.has(*field)) {
printedFields.add(kj::strTree(
field->getProto().getName(), " = ",
print(structValue.get(*field), whichFieldType(*field), indent.next(), PREFIXED)));
}
}
if (mode == PARENTHESIZED) {
return indent.delimit(printedMembers.releaseAsArray(), mode);
} else {
return kj::strTree('(', indent.delimit(printedMembers.releaseAsArray(), mode), ')');
for (auto field: nonUnionFields) {
if (structValue.has(field)) {
printedFields.add(kj::strTree(
field.getProto().getName(), " = ",
print(structValue.get(field), whichFieldType(field), indent.next(), PREFIXED)));
}
}
}
case DynamicValue::UNION: {
auto unionValue = value.as<DynamicUnion>();
KJ_IF_MAYBE(tag, unionValue.which()) {
return kj::strTree(
tag->getProto().getName(), '(',
print(unionValue.get(), whichMemberType(*tag), indent, PARENTHESIZED), ')');
if (mode == PARENTHESIZED) {
return indent.delimit(printedFields.releaseAsArray(), mode);
} else {
// Unknown union member; must have come from newer
// version of the protocol.
return kj::strTree("<unknown union member>");
return kj::strTree('(', indent.delimit(printedFields.releaseAsArray(), mode), ')');
}
}
case DynamicValue::INTERFACE:
......@@ -240,17 +229,17 @@ static kj::StringTree print(const DynamicValue::Reader& value,
}
kj::StringTree stringify(DynamicValue::Reader value) {
return print(value, schema::Type::Body::STRUCT_TYPE, Indent(false), BARE);
return print(value, schema2::Type::STRUCT, Indent(false), BARE);
}
} // namespace
kj::StringTree prettyPrint(DynamicStruct::Reader value) {
return print(value, schema::Type::Body::STRUCT_TYPE, Indent(true), BARE);
return print(value, schema2::Type::STRUCT, Indent(true), BARE);
}
kj::StringTree prettyPrint(DynamicList::Reader value) {
return print(value, schema::Type::Body::LIST_TYPE, Indent(true), BARE);
return print(value, schema2::Type::LIST, Indent(true), BARE);
}
kj::StringTree prettyPrint(DynamicStruct::Builder value) { return prettyPrint(value.asReader()); }
......@@ -260,8 +249,6 @@ kj::StringTree KJ_STRINGIFY(const DynamicValue::Reader& value) { return stringif
kj::StringTree KJ_STRINGIFY(const DynamicValue::Builder& value) { return stringify(value.asReader()); }
kj::StringTree KJ_STRINGIFY(DynamicEnum value) { return stringify(value); }
kj::StringTree KJ_STRINGIFY(const DynamicObject& value) { return stringify(value); }
kj::StringTree KJ_STRINGIFY(const DynamicUnion::Reader& value) { return stringify(value); }
kj::StringTree KJ_STRINGIFY(const DynamicUnion::Builder& value) { return stringify(value.asReader()); }
kj::StringTree KJ_STRINGIFY(const DynamicStruct::Reader& value) { return stringify(value); }
kj::StringTree KJ_STRINGIFY(const DynamicStruct::Builder& value) { return stringify(value.asReader()); }
kj::StringTree KJ_STRINGIFY(const DynamicList::Reader& value) { return stringify(value); }
......@@ -273,11 +260,6 @@ kj::StringTree structString(StructReader reader, const RawSchema& schema) {
return stringify(DynamicStruct::Reader(StructSchema(&schema), reader));
}
kj::StringTree unionString(StructReader reader, const RawSchema& schema, uint memberIndex) {
return stringify(DynamicUnion::Reader(
StructSchema(&schema).getMembers()[memberIndex].asUnion(), reader));
}
} // namespace _ (private)
} // namespace capnp
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