Commit d7b612a1 authored by Kenton Varda's avatar Kenton Varda

Generics: Schema parser.

parent 4023a354
...@@ -5,17 +5,18 @@ ...@@ -5,17 +5,18 @@
namespace capnp { namespace capnp {
namespace schemas { namespace schemas {
static const ::capnp::_::AlignedData<19> b_b9c6f99ebf805f2c = { static const ::capnp::_::AlignedData<21> b_b9c6f99ebf805f2c = {
{ 0, 0, 0, 0, 5, 0, 5, 0, { 0, 0, 0, 0, 5, 0, 6, 0,
44, 95, 128, 191, 158, 249, 198, 185, 44, 95, 128, 191, 158, 249, 198, 185,
16, 0, 0, 0, 5, 0, 1, 0, 16, 0, 0, 0, 5, 0, 1, 0,
129, 78, 48, 184, 123, 125, 248, 189, 129, 78, 48, 184, 123, 125, 248, 189,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
17, 0, 0, 0, 210, 0, 0, 0, 21, 0, 0, 0, 210, 0, 0, 0,
29, 0, 0, 0, 7, 0, 0, 0, 33, 0, 0, 0, 7, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
28, 0, 0, 0, 3, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
24, 0, 0, 0, 2, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
99, 97, 112, 110, 112, 47, 99, 43, 99, 97, 112, 110, 112, 47, 99, 43,
43, 46, 99, 97, 112, 110, 112, 58, 43, 46, 99, 97, 112, 110, 112, 58,
...@@ -23,35 +24,38 @@ static const ::capnp::_::AlignedData<19> b_b9c6f99ebf805f2c = { ...@@ -23,35 +24,38 @@ static const ::capnp::_::AlignedData<19> b_b9c6f99ebf805f2c = {
101, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0,
12, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, } 0, 0, 0, 0, 0, 0, 0, 0, }
}; };
const ::capnp::_::RawSchema s_b9c6f99ebf805f2c = { const ::capnp::_::RawSchema s_b9c6f99ebf805f2c = {
0xb9c6f99ebf805f2c, b_b9c6f99ebf805f2c.words, 19, nullptr, nullptr, 0xb9c6f99ebf805f2c, b_b9c6f99ebf805f2c.words, 21, nullptr, nullptr,
0, 0, nullptr, nullptr, nullptr 0, 0, nullptr, nullptr, nullptr
}; };
static const ::capnp::_::AlignedData<18> b_f264a779fef191ce = { static const ::capnp::_::AlignedData<20> b_f264a779fef191ce = {
{ 0, 0, 0, 0, 5, 0, 5, 0, { 0, 0, 0, 0, 5, 0, 6, 0,
206, 145, 241, 254, 121, 167, 100, 242, 206, 145, 241, 254, 121, 167, 100, 242,
16, 0, 0, 0, 5, 0, 252, 7, 16, 0, 0, 0, 5, 0, 252, 7,
129, 78, 48, 184, 123, 125, 248, 189, 129, 78, 48, 184, 123, 125, 248, 189,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
17, 0, 0, 0, 170, 0, 0, 0, 21, 0, 0, 0, 170, 0, 0, 0,
25, 0, 0, 0, 7, 0, 0, 0, 29, 0, 0, 0, 7, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
24, 0, 0, 0, 3, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
20, 0, 0, 0, 2, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
99, 97, 112, 110, 112, 47, 99, 43, 99, 97, 112, 110, 112, 47, 99, 43,
43, 46, 99, 97, 112, 110, 112, 58, 43, 46, 99, 97, 112, 110, 112, 58,
110, 97, 109, 101, 0, 0, 0, 0, 110, 97, 109, 101, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0,
12, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, } 0, 0, 0, 0, 0, 0, 0, 0, }
}; };
const ::capnp::_::RawSchema s_f264a779fef191ce = { const ::capnp::_::RawSchema s_f264a779fef191ce = {
0xf264a779fef191ce, b_f264a779fef191ce.words, 18, nullptr, nullptr, 0xf264a779fef191ce, b_f264a779fef191ce.words, 20, nullptr, nullptr,
0, 0, nullptr, nullptr, nullptr 0, 0, nullptr, nullptr, nullptr
}; };
} // namespace schemas } // namespace schemas
......
...@@ -1013,7 +1013,7 @@ public: ...@@ -1013,7 +1013,7 @@ public:
kj::BufferedOutputStreamWrapper output(rawOutput); kj::BufferedOutputStreamWrapper output(rawOutput);
while (parserInput.getPosition() != tokens.end()) { while (parserInput.getPosition() != tokens.end()) {
KJ_IF_MAYBE(expression, parser.getParsers().parenthesizedValueExpression(parserInput)) { KJ_IF_MAYBE(expression, parser.getParsers().expression(parserInput)) {
MallocMessageBuilder item( MallocMessageBuilder item(
segmentSize == 0 ? SUGGESTED_FIRST_SEGMENT_WORDS : segmentSize, segmentSize == 0 ? SUGGESTED_FIRST_SEGMENT_WORDS : segmentSize,
segmentSize == 0 ? SUGGESTED_ALLOCATION_STRATEGY : AllocationStrategy::FIXED_SIZE); segmentSize == 0 ? SUGGESTED_ALLOCATION_STRATEGY : AllocationStrategy::FIXED_SIZE);
...@@ -1243,25 +1243,8 @@ private: ...@@ -1243,25 +1243,8 @@ private:
return loader.get(id); return loader.get(id);
} }
kj::Maybe<DynamicValue::Reader> resolveConstant(DeclName::Reader name) { kj::Maybe<DynamicValue::Reader> resolveConstant(Expression::Reader name) {
auto base = name.getBase(); errorReporter.addErrorOn(name, kj::str("External constants not allowed in encode input."));
switch (base.which()) {
case DeclName::Base::RELATIVE_NAME: {
auto value = base.getRelativeName();
errorReporter.addErrorOn(value, kj::str("Not defined: ", value.getValue()));
break;
}
case DeclName::Base::ABSOLUTE_NAME: {
auto value = base.getAbsoluteName();
errorReporter.addErrorOn(value, kj::str("Not defined: ", value.getValue()));
break;
}
case DeclName::Base::IMPORT_NAME: {
auto value = base.getImportName();
errorReporter.addErrorOn(value, "Imports not allowed in encode input.");
break;
}
}
return nullptr; return nullptr;
} }
......
...@@ -103,7 +103,7 @@ void enumerateDeps(schema::Node::Reader node, std::set<uint64_t>& deps) { ...@@ -103,7 +103,7 @@ void enumerateDeps(schema::Node::Reader node, std::set<uint64_t>& deps) {
case schema::Node::INTERFACE: { case schema::Node::INTERFACE: {
auto interfaceNode = node.getInterface(); auto interfaceNode = node.getInterface();
for (auto extend: interfaceNode.getExtends()) { for (auto extend: interfaceNode.getExtends()) {
deps.insert(extend); deps.insert(extend.getId());
} }
for (auto method: interfaceNode.getMethods()) { for (auto method: interfaceNode.getMethods()) {
deps.insert(method.getParamStructType()); deps.insert(method.getParamStructType());
...@@ -1327,8 +1327,8 @@ private: ...@@ -1327,8 +1327,8 @@ private:
auto proto = schema.getProto(); auto proto = schema.getProto();
auto extends = KJ_MAP(id, proto.getInterface().getExtends()) { auto extends = KJ_MAP(extend, proto.getInterface().getExtends()) {
Schema schema = schemaLoader.get(id); Schema schema = schemaLoader.get(extend.getId());
return ExtendInfo { cppFullName(schema).flatten(), schema.getProto().getId() }; return ExtendInfo { cppFullName(schema).flatten(), schema.getProto().getId() };
}; };
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <unordered_map> #include <unordered_map>
#include <kj/main.h> #include <kj/main.h>
#include <algorithm> #include <algorithm>
#include <map>
#if HAVE_CONFIG_H #if HAVE_CONFIG_H
#include "config.h" #include "config.h"
...@@ -113,15 +114,22 @@ private: ...@@ -113,15 +114,22 @@ private:
return "(?)"; return "(?)";
} }
kj::StringTree nodeName(Schema target, Schema scope) { kj::StringTree nodeName(Schema target, Schema scope, schema::TypeEnvironment::Reader env) {
kj::Vector<Schema> targetParents; kj::Vector<Schema> targetPath;
kj::Vector<Schema> scopeParts; kj::Vector<Schema> scopeParts;
targetPath.add(target);
std::map<uint64_t, List<schema::TypeEnvironment::Binding>::Reader> scopeBindings;
for (auto scopeEnv: env.getScopes()) {
scopeBindings[scopeEnv.getScopeId()] = scopeEnv.getBindings();
}
{ {
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.add(parent); targetPath.add(parent);
} }
} }
...@@ -134,28 +142,45 @@ private: ...@@ -134,28 +142,45 @@ private:
} }
} }
// Remove common scope. // Remove common scope (unless it has been reparameterized).
while (!scopeParts.empty() && !targetParents.empty() && // TODO(someday): This is broken in that we aren't checking for shadowing.
scopeParts.back() == targetParents.back()) { while (!scopeParts.empty() && targetPath.size() > 1 &&
scopeParts.back() == targetPath.back() &&
scopeBindings.count(scopeParts.back().getProto().getId()) == 0) {
scopeParts.removeLast(); scopeParts.removeLast();
targetParents.removeLast(); targetPath.removeLast();
} }
// TODO(someday): This is broken in that we aren't checking for shadowing. auto parts = kj::heapArrayBuilder<kj::StringTree>(targetPath.size());
while (!targetPath.empty()) {
kj::StringTree path = kj::strTree(); auto part = targetPath.back();
while (!targetParents.empty()) {
auto part = targetParents.back();
auto proto = part.getProto(); auto proto = part.getProto();
kj::StringTree partStr;
if (proto.getScopeId() == 0) { if (proto.getScopeId() == 0) {
path = kj::strTree(kj::mv(path), "import \"/", proto.getDisplayName(), "\"."); partStr = kj::strTree("import \"/", proto.getDisplayName(), '\"');
} else { } else {
path = kj::strTree(kj::mv(path), getUnqualifiedName(part), "."); partStr = kj::strTree(getUnqualifiedName(part));
} }
targetParents.removeLast();
auto iter = scopeBindings.find(proto.getId());
if (iter != scopeBindings.end()) {
auto bindings = KJ_MAP(binding, iter->second) {
switch (binding.which()) {
case schema::TypeEnvironment::Binding::UNBOUND:
return kj::strTree("AnyPointer");
case schema::TypeEnvironment::Binding::TYPE:
return genType(binding.getType(), scope);
}
return kj::strTree("<unknown binding>");
};
partStr = kj::strTree(kj::mv(partStr), "(", kj::StringTree(kj::mv(bindings), ", "), ")");
}
parts.add(kj::mv(partStr));
targetPath.removeLast();
} }
return kj::strTree(kj::mv(path), getUnqualifiedName(target)); return kj::StringTree(parts.finish(), ".");
} }
kj::StringTree genType(schema::Type::Reader type, Schema scope) { kj::StringTree genType(schema::Type::Reader type, Schema scope) {
...@@ -177,12 +202,33 @@ private: ...@@ -177,12 +202,33 @@ private:
case schema::Type::LIST: case schema::Type::LIST:
return kj::strTree("List(", genType(type.getList().getElementType(), scope), ")"); return kj::strTree("List(", genType(type.getList().getElementType(), scope), ")");
case schema::Type::ENUM: case schema::Type::ENUM:
return nodeName(schemaLoader.get(type.getEnum().getTypeId()), scope); return nodeName(schemaLoader.get(type.getEnum().getTypeId()), scope,
type.getEnum().getTypeEnvironment());
case schema::Type::STRUCT: case schema::Type::STRUCT:
return nodeName(schemaLoader.get(type.getStruct().getTypeId()), scope); return nodeName(schemaLoader.get(type.getStruct().getTypeId()), scope,
type.getStruct().getTypeEnvironment());
case schema::Type::INTERFACE: case schema::Type::INTERFACE:
return nodeName(schemaLoader.get(type.getInterface().getTypeId()), scope); return nodeName(schemaLoader.get(type.getInterface().getTypeId()), scope,
case schema::Type::ANY_POINTER: return kj::strTree("AnyPointer"); type.getInterface().getTypeEnvironment());
case schema::Type::ANY_POINTER: {
auto anyPointer = type.getAnyPointer();
switch (anyPointer.which()) {
case schema::Type::AnyPointer::UNCONSTRAINED:
return kj::strTree("AnyPointer");
case schema::Type::AnyPointer::PARAMETER: {
auto param = anyPointer.getParameter();
auto scopeProto = scope.getProto();
auto targetScopeId = param.getNodeId();
while (scopeProto.getId() != targetScopeId) {
scopeProto = schemaLoader.get(param.getNodeId()).getProto();
}
auto params = scopeProto.getParameters();
KJ_REQUIRE(param.getParameterIndex() < params.size());
return kj::strTree(params[param.getParameterIndex()].getName());
}
}
KJ_UNREACHABLE;
}
} }
return kj::strTree(); return kj::strTree();
} }
...@@ -286,6 +332,19 @@ private: ...@@ -286,6 +332,19 @@ private:
return kj::strTree(""); return kj::strTree("");
} }
kj::StringTree genGenericParams(List<schema::Node::Parameter>::Reader params, Schema scope) {
if (params.size() == 0) {
return kj::strTree();
}
return kj::strTree(" (", kj::StringTree(
KJ_MAP(param, params) { return kj::strTree(param.getName()); }, ", "), ')');
}
kj::StringTree genGenericParams(Schema schema) {
auto proto = schema.getProto();
return genGenericParams(proto.getParameters(), schemaLoader.get(proto.getScopeId()));
}
kj::StringTree genAnnotation(schema::Annotation::Reader annotation, kj::StringTree genAnnotation(schema::Annotation::Reader annotation,
Schema scope, Schema scope,
const char* prefix = " ", const char* suffix = "") { const char* prefix = " ", const char* suffix = "") {
...@@ -296,9 +355,11 @@ private: ...@@ -296,9 +355,11 @@ private:
auto value = genValue(annDecl.getType(), annotation.getValue(), decl).flatten(); auto value = genValue(annDecl.getType(), annotation.getValue(), decl).flatten();
if (value.startsWith("(")) { if (value.startsWith("(")) {
return kj::strTree(prefix, "$", nodeName(decl, scope), value, suffix); return kj::strTree(prefix, "$", nodeName(decl, scope, annotation.getTypeEnvironment()),
value, suffix);
} else { } else {
return kj::strTree(prefix, "$", nodeName(decl, scope), "(", value, ")", suffix); return kj::strTree(prefix, "$", nodeName(decl, scope, annotation.getTypeEnvironment()),
"(", value, ")", suffix);
} }
} }
...@@ -402,7 +463,8 @@ private: ...@@ -402,7 +463,8 @@ private:
return kj::strTree(); return kj::strTree();
} }
kj::StringTree genParamList(InterfaceSchema interface, StructSchema schema) { kj::StringTree genParamList(InterfaceSchema interface, StructSchema schema,
schema::TypeEnvironment::Reader env) {
if (schema.getProto().getScopeId() == 0) { if (schema.getProto().getScopeId() == 0) {
// A named parameter list. // A named parameter list.
return kj::strTree("(", kj::StringTree( return kj::strTree("(", kj::StringTree(
...@@ -418,7 +480,7 @@ private: ...@@ -418,7 +480,7 @@ private:
genAnnotations(proto.getAnnotations(), interface)); genAnnotations(proto.getAnnotations(), interface));
}, ", "), ")"); }, ", "), ")");
} else { } else {
return nodeName(schema, interface); return nodeName(schema, interface, env);
} }
} }
...@@ -428,8 +490,9 @@ private: ...@@ -428,8 +490,9 @@ private:
return kj::strTree(); return kj::strTree();
} else { } else {
return kj::strTree(" extends(", kj::StringTree( return kj::strTree(" extends(", kj::StringTree(
KJ_MAP(id, extends) { KJ_MAP(extend, extends) {
return nodeName(schemaLoader.get(id), interface); return nodeName(schemaLoader.get(extend.getId()), interface,
extend.getEnvironment());
}, ", "), ")"); }, ", "), ")");
} }
} }
...@@ -449,7 +512,8 @@ private: ...@@ -449,7 +512,8 @@ private:
auto structProto = proto.getStruct(); auto structProto = proto.getStruct();
return kj::strTree( return kj::strTree(
indent, "struct ", name, indent, "struct ", name,
" @0x", kj::hex(proto.getId()), genAnnotations(schema), " { # ", " @0x", kj::hex(proto.getId()), genGenericParams(schema),
genAnnotations(schema), " { # ",
structProto.getDataWordCount() * 8, " bytes, ", structProto.getDataWordCount() * 8, " bytes, ",
structProto.getPointerCount(), " ptrs", structProto.getPointerCount(), " ptrs",
structProto.getPreferredListEncoding() == schema::ElementSize::INLINE_COMPOSITE structProto.getPreferredListEncoding() == schema::ElementSize::INLINE_COMPOSITE
...@@ -475,7 +539,7 @@ private: ...@@ -475,7 +539,7 @@ private:
case schema::Node::INTERFACE: { case schema::Node::INTERFACE: {
auto interface = schema.asInterface(); auto interface = schema.asInterface();
return kj::strTree( return kj::strTree(
indent, "interface ", name, " @0x", kj::hex(proto.getId()), indent, "interface ", name, " @0x", kj::hex(proto.getId()), genGenericParams(schema),
genExtends(interface), genExtends(interface),
genAnnotations(schema), " {\n", genAnnotations(schema), " {\n",
KJ_MAP(method, sortByCodeOrder(interface.getMethods())) { KJ_MAP(method, sortByCodeOrder(interface.getMethods())) {
...@@ -484,7 +548,8 @@ private: ...@@ -484,7 +548,8 @@ private:
auto results = schemaLoader.get(methodProto.getResultStructType()).asStruct(); auto results = schemaLoader.get(methodProto.getResultStructType()).asStruct();
return kj::strTree( return kj::strTree(
indent.next(), methodProto.getName(), " @", method.getIndex(), " ", indent.next(), methodProto.getName(), " @", method.getIndex(), " ",
genParamList(interface, params), " -> ", genParamList(interface, results), genParamList(interface, params, methodProto.getParamEnvironment()), " -> ",
genParamList(interface, results, methodProto.getResultEnvironment()),
genAnnotations(methodProto.getAnnotations(), interface), ";\n"); genAnnotations(methodProto.getAnnotations(), interface), ";\n");
}, },
genNestedDecls(schema, indent.next()), genNestedDecls(schema, indent.next()),
......
This diff is collapsed.
...@@ -73,64 +73,64 @@ static Declaration::Builder addNested(Declaration::Builder parent) { ...@@ -73,64 +73,64 @@ static Declaration::Builder addNested(Declaration::Builder parent) {
struct TypeOption { struct TypeOption {
kj::StringPtr name; kj::StringPtr name;
kj::ConstFunction<void(ValueExpression::Builder)> makeValue; kj::ConstFunction<void(Expression::Builder)> makeValue;
}; };
static const TypeOption TYPE_OPTIONS[] = { static const TypeOption TYPE_OPTIONS[] = {
{ "Int32", { "Int32",
[](ValueExpression::Builder builder) { [](Expression::Builder builder) {
builder.setPositiveInt(rand() % (1 << 24)); builder.setPositiveInt(rand() % (1 << 24));
}}, }},
{ "Float64", { "Float64",
[](ValueExpression::Builder builder) { [](Expression::Builder builder) {
builder.setPositiveInt(rand()); builder.setPositiveInt(rand());
}}, }},
{ "Int8", { "Int8",
[](ValueExpression::Builder builder) { [](Expression::Builder builder) {
builder.setPositiveInt(rand() % 128); builder.setPositiveInt(rand() % 128);
}}, }},
{ "UInt16", { "UInt16",
[](ValueExpression::Builder builder) { [](Expression::Builder builder) {
builder.setPositiveInt(rand() % (1 << 16)); builder.setPositiveInt(rand() % (1 << 16));
}}, }},
{ "Bool", { "Bool",
[](ValueExpression::Builder builder) { [](Expression::Builder builder) {
builder.initName().getBase().initRelativeName().setValue("true"); builder.initRelativeName().setValue("true");
}}, }},
{ "Text", { "Text",
[](ValueExpression::Builder builder) { [](Expression::Builder builder) {
builder.setString(chooseFrom(RFC3092)); builder.setString(chooseFrom(RFC3092));
}}, }},
{ "StructType", { "StructType",
[](ValueExpression::Builder builder) { [](Expression::Builder builder) {
auto assignment = builder.initStruct(1)[0]; auto assignment = builder.initTuple(1)[0];
assignment.initFieldName().setValue("i"); assignment.initNamed().setValue("i");
assignment.initValue().setPositiveInt(rand() % (1 << 24)); assignment.initValue().setPositiveInt(rand() % (1 << 24));
}}, }},
{ "EnumType", { "EnumType",
[](ValueExpression::Builder builder) { [](Expression::Builder builder) {
builder.initName().getBase().initRelativeName().setValue(chooseFrom(RFC3092)); builder.initRelativeName().setValue(chooseFrom(RFC3092));
}}, }},
}; };
void setDeclName(DeclName::Builder decl, kj::StringPtr name) { void setDeclName(Expression::Builder decl, kj::StringPtr name) {
decl.getBase().initRelativeName().setValue(name); decl.initRelativeName().setValue(name);
} }
static kj::ConstFunction<void(ValueExpression::Builder)> randomizeType( static kj::ConstFunction<void(Expression::Builder)> randomizeType(Expression::Builder type) {
TypeExpression::Builder type) {
auto option = &chooseFrom(TYPE_OPTIONS); auto option = &chooseFrom(TYPE_OPTIONS);
if (rand() % 4 == 0) { if (rand() % 4 == 0) {
setDeclName(type.initName(), "List"); auto app = type.initApplication();
setDeclName(type.initParams(1)[0].initName(), option->name); setDeclName(app.initFunction(), "List");
return [option](ValueExpression::Builder builder) { setDeclName(app.initParams(1)[0].initValue(), option->name);
return [option](Expression::Builder builder) {
for (auto element: builder.initList(rand() % 4 + 1)) { for (auto element: builder.initList(rand() % 4 + 1)) {
option->makeValue(element); option->makeValue(element);
} }
}; };
} else { } else {
setDeclName(type.initName(), option->name); setDeclName(type, option->name);
return option->makeValue.reference(); return option->makeValue.reference();
} }
} }
...@@ -324,13 +324,14 @@ static ChangeInfo fieldUpgradeList(Declaration::Builder decl, uint& nextOrdinal, ...@@ -324,13 +324,14 @@ static ChangeInfo fieldUpgradeList(Declaration::Builder decl, uint& nextOrdinal,
return { NO_CHANGE, "Upgrade primitive list to struct list, but it had a default value." }; return { NO_CHANGE, "Upgrade primitive list to struct list, but it had a default value." };
} }
auto typeParams = field.getType().getParams(); auto type = field.getType();
if (typeParams.size() != 1) { if (!type.isApplication()) {
return { NO_CHANGE, "Upgrade primitive list to struct list, but it wasn't a list." }; return { NO_CHANGE, "Upgrade primitive list to struct list, but it wasn't a list." };
} }
auto typeParams = type.getApplication().getParams();
auto elementType = typeParams[0]; auto elementType = typeParams[0].getValue();
auto relativeName = elementType.getName().getBase().getRelativeName(); auto relativeName = elementType.getRelativeName();
auto nameText = relativeName.asReader().getValue(); auto nameText = relativeName.asReader().getValue();
if (nameText == "StructType" || nameText.endsWith("Struct")) { if (nameText == "StructType" || nameText.endsWith("Struct")) {
return { NO_CHANGE, "Upgrade primitive list to struct list, but it was already a struct list."}; return { NO_CHANGE, "Upgrade primitive list to struct list, but it was already a struct list."};
...@@ -380,15 +381,15 @@ static ChangeInfo fieldChangeType(Declaration::Builder decl, uint& nextOrdinal, ...@@ -380,15 +381,15 @@ static ChangeInfo fieldChangeType(Declaration::Builder decl, uint& nextOrdinal,
if (field.getDefaultValue().isNone()) { if (field.getDefaultValue().isNone()) {
// Change the type. // Change the type.
auto type = field.getType(); auto type = field.getType();
while (type.getParams().size() > 0) { while (type.isApplication()) {
// Either change the list parameter, or revert to a non-list. // Either change the list parameter, or revert to a non-list.
if (rand() % 2) { if (rand() % 2) {
type = type.getParams()[0]; type = type.getApplication().getParams()[0].getValue();
} else { } else {
type.disownParams(); type.initRelativeName();
} }
} }
auto typeName = type.getName().getBase().getRelativeName(); auto typeName = type.getRelativeName();
if (typeName.asReader().getValue().startsWith("Text")) { if (typeName.asReader().getValue().startsWith("Text")) {
typeName.setValue("Int32"); typeName.setValue("Int32");
} else { } else {
...@@ -399,12 +400,12 @@ static ChangeInfo fieldChangeType(Declaration::Builder decl, uint& nextOrdinal, ...@@ -399,12 +400,12 @@ static ChangeInfo fieldChangeType(Declaration::Builder decl, uint& nextOrdinal,
// Change the default value. // Change the default value.
auto dval = field.getDefaultValue().getValue(); auto dval = field.getDefaultValue().getValue();
switch (dval.which()) { switch (dval.which()) {
case ValueExpression::UNKNOWN: KJ_FAIL_ASSERT("unknown value expression?"); case Expression::UNKNOWN: KJ_FAIL_ASSERT("unknown value expression?");
case ValueExpression::POSITIVE_INT: dval.setPositiveInt(dval.getPositiveInt() ^ 1); break; case Expression::POSITIVE_INT: dval.setPositiveInt(dval.getPositiveInt() ^ 1); break;
case ValueExpression::NEGATIVE_INT: dval.setNegativeInt(dval.getNegativeInt() ^ 1); break; case Expression::NEGATIVE_INT: dval.setNegativeInt(dval.getNegativeInt() ^ 1); break;
case ValueExpression::FLOAT: dval.setFloat(-dval.getFloat()); break; case Expression::FLOAT: dval.setFloat(-dval.getFloat()); break;
case ValueExpression::NAME: { case Expression::RELATIVE_NAME: {
auto name = dval.getName().getBase().getRelativeName(); auto name = dval.getRelativeName();
auto nameText = name.asReader().getValue(); auto nameText = name.asReader().getValue();
if (nameText == "true") { if (nameText == "true") {
name.setValue("false"); name.setValue("false");
...@@ -417,10 +418,17 @@ static ChangeInfo fieldChangeType(Declaration::Builder decl, uint& nextOrdinal, ...@@ -417,10 +418,17 @@ static ChangeInfo fieldChangeType(Declaration::Builder decl, uint& nextOrdinal,
} }
break; break;
} }
case ValueExpression::STRING: case Expression::STRING:
case ValueExpression::LIST: case Expression::BINARY:
case ValueExpression::STRUCT: case Expression::LIST:
case Expression::TUPLE:
return { NO_CHANGE, "Change the default value of a field, but it's a pointer field." }; return { NO_CHANGE, "Change the default value of a field, but it's a pointer field." };
case Expression::ABSOLUTE_NAME:
case Expression::IMPORT:
case Expression::APPLICATION:
case Expression::MEMBER:
KJ_FAIL_ASSERT("Unexpected expression type.");
} }
return { INCOMPATIBLE, "Change the default value of a pritimive field." }; return { INCOMPATIBLE, "Change the default value of a pritimive field." };
} }
...@@ -764,7 +772,7 @@ void doTest() { ...@@ -764,7 +772,7 @@ void doTest() {
fieldDecl.initName().setValue("i"); fieldDecl.initName().setValue("i");
fieldDecl.getId().initOrdinal().setValue(0); fieldDecl.getId().initOrdinal().setValue(0);
auto field = fieldDecl.initField(); auto field = fieldDecl.initField();
setDeclName(field.initType().initName(), "UInt32"); setDeclName(field.initType(), "UInt32");
} }
{ {
auto decl = decls[2]; auto decl = decls[2];
...@@ -793,7 +801,7 @@ void doTest() { ...@@ -793,7 +801,7 @@ void doTest() {
fieldDecl.initName().setValue("f0"); fieldDecl.initName().setValue("f0");
fieldDecl.getId().initOrdinal().setValue(0); fieldDecl.getId().initOrdinal().setValue(0);
auto field = fieldDecl.initField(); auto field = fieldDecl.initField();
setDeclName(field.initType().initName(), option.name); setDeclName(field.initType(), option.name);
uint ordinal = 1; uint ordinal = 1;
for (auto j: kj::range(0, rand() % 4)) { for (auto j: kj::range(0, rand() % 4)) {
......
...@@ -50,45 +50,9 @@ struct LocatedFloat { ...@@ -50,45 +50,9 @@ struct LocatedFloat {
endByte @2 :UInt32; endByte @2 :UInt32;
} }
struct DeclName { struct Expression {
# An expressing naming a thing declared elsewhere. Examples: # An expression. May evaluate to a type, a value, or a declaration (i.e. some named thing which
# * `MyType` # is neither a type nor a value, like an annotation declaration).
# * `foo.bar.Baz`
# * `.absolute.path.to.SomeType`
# * `import "foo.capnp"`
base :union {
# The first element of the name.
absoluteName @0 :LocatedText; # A symbol at the global scope.
relativeName @1 :LocatedText; # A symbol that should be looked up lexically.
importName @2 :LocatedText; # A file name to import.
}
memberPath @3 :List(LocatedText);
# List of `.member` suffixes.
startByte @4 :UInt32;
endByte @5 :UInt32;
}
struct TypeExpression {
# An expression evaluating to a type.
name @0 :DeclName;
# Name of the type declaration.
params @1 :List(TypeExpression);
# Type parameters, if any. E.g. `List(Foo)` has one type parameter `Foo`.
#
# If a param failed to parse, its `name` may be null, and it should be ignored.
startByte @2 :UInt32;
endByte @3 :UInt32;
}
struct ValueExpression {
# An expression evaluating to a value.
union { union {
unknown @0 :Void; # e.g. parse error; downstream should ignore unknown @0 :Void; # e.g. parse error; downstream should ignore
...@@ -97,14 +61,48 @@ struct ValueExpression { ...@@ -97,14 +61,48 @@ struct ValueExpression {
float @3 :Float64; float @3 :Float64;
string @4 :Text; string @4 :Text;
binary @10 :Data; binary @10 :Data;
name @5 :DeclName;
list @6 :List(ValueExpression); relativeName @5 :LocatedText;
struct @7 :List(FieldAssignment); # Just an identifier.
absoluteName @15 :LocatedText;
# An identifier with leading '.'.
import @16 :LocatedText;
# An import directive.
list @6 :List(Expression);
# Bracketed list; members are never named.
tuple @7 :List(Param);
# Parenthesized list, possibly with named members.
#
# Note that a parenthesized list with one unnamed member is just a parenthesized expression,
# not a tuple, and so will never be represented as a tuple.
application :group {
# Application of a function to some parameters, e.g. "foo(bar, baz)".
function @11 :Expression;
params @12 :List(Param);
}
member :group {
# A named member of an aggregate, e.g. "foo.bar".
parent @13 :Expression;
name @14 :LocatedText;
}
# TODO(someday): Basic arithmetic?
} }
struct FieldAssignment { struct Param {
fieldName @0 :LocatedText; union {
value @1 :ValueExpression; unnamed @0 :Void; # Just a value.
named @1 :LocatedText; # "name = value"
}
value @2 :Expression;
} }
startByte @8 :UInt32; startByte @8 :UInt32;
...@@ -122,15 +120,24 @@ struct Declaration { ...@@ -122,15 +120,24 @@ struct Declaration {
ordinal @3 :LocatedInteger; # limited to 16 bits ordinal @3 :LocatedInteger; # limited to 16 bits
} }
parameters @57 :List(TypeParameter);
# If this node is parameterized (generic), the list of parameters. Empty for non-generic types.
struct TypeParameter {
name @0 :Text;
startByte @1 :UInt32;
endByte @2 :UInt32;
}
nestedDecls @4 :List(Declaration); nestedDecls @4 :List(Declaration);
annotations @5 :List(AnnotationApplication); annotations @5 :List(AnnotationApplication);
struct AnnotationApplication { struct AnnotationApplication {
name @0 :DeclName; name @0 :Expression;
value :union { value :union {
none @1 :Void; # None specified; implies void value. none @1 :Void; # None specified; implies void value.
expression @2 :ValueExpression; expression @2 :Expression;
} }
} }
...@@ -143,12 +150,12 @@ struct Declaration { ...@@ -143,12 +150,12 @@ struct Declaration {
file @9 :Void; file @9 :Void;
using :group { using :group {
target @10 :DeclName; target @10 :Expression;
} }
const :group { const :group {
type @11 :TypeExpression; type @11 :Expression;
value @12 :ValueExpression; value @12 :Expression;
} }
enum @13 :Void; enum @13 :Void;
...@@ -156,17 +163,17 @@ struct Declaration { ...@@ -156,17 +163,17 @@ struct Declaration {
struct @15 :Void; struct @15 :Void;
field :group { field :group {
type @16 :TypeExpression; type @16 :Expression;
defaultValue :union { defaultValue :union {
none @17 :Void; none @17 :Void;
value @18 :ValueExpression; value @18 :Expression;
} }
} }
union @19 :Void; union @19 :Void;
group @20 :Void; group @20 :Void;
interface :group { interface :group {
extends @21 :List(DeclName); extends @21 :List(Expression);
} }
method :group { method :group {
params @22 :ParamList; params @22 :ParamList;
...@@ -177,7 +184,7 @@ struct Declaration { ...@@ -177,7 +184,7 @@ struct Declaration {
} }
annotation :group { annotation :group {
type @25 :TypeExpression; type @25 :Expression;
targetsFile @26 :Bool; targetsFile @26 :Bool;
targetsConst @27 :Bool; targetsConst @27 :Bool;
...@@ -216,18 +223,20 @@ struct Declaration { ...@@ -216,18 +223,20 @@ struct Declaration {
builtinFloat64 @51 :Void; builtinFloat64 @51 :Void;
builtinText @52 :Void; builtinText @52 :Void;
builtinData @53 :Void; builtinData @53 :Void;
builtinList @54 :Void; builtinList @54 :Void $builtinParams([(name = "Element")]);
builtinObject @55 :Void; # only for "renamed to AnyPointer" error message builtinObject @55 :Void; # only for "renamed to AnyPointer" error message
builtinAnyPointer @56 :Void; builtinAnyPointer @56 :Void;
} }
annotation builtinParams @0x94099c3f9eb32d6b (field) :List(TypeParameter);
struct ParamList { struct ParamList {
# A list of method parameters or method returns. # A list of method parameters or method returns.
union { union {
namedList @0 :List(Param); namedList @0 :List(Param);
type @1 :DeclName; type @1 :Expression;
# Specified some other struct type instead of a named list. # Specified some other struct type instead of a named list.
} }
...@@ -236,11 +245,11 @@ struct Declaration { ...@@ -236,11 +245,11 @@ struct Declaration {
} }
struct Param { struct Param {
name @0 :LocatedText; # If null, param failed to parse. name @0 :LocatedText; # If null, param failed to parse.
type @1 :TypeExpression; type @1 :Expression;
annotations @2 :List(AnnotationApplication); annotations @2 :List(AnnotationApplication);
defaultValue :union { defaultValue :union {
none @3 :Void; none @3 :Void;
value @4 :ValueExpression; value @4 :Expression;
} }
startByte @5 :UInt32; startByte @5 :UInt32;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -176,7 +176,8 @@ Lexer::Lexer(Orphanage orphanageParam, ErrorReporter& errorReporterParam) ...@@ -176,7 +176,8 @@ Lexer::Lexer(Orphanage orphanageParam, ErrorReporter& errorReporterParam)
p::transformWithLocation(p::doubleQuotedHexBinary, p::transformWithLocation(p::doubleQuotedHexBinary,
[this](Location loc, kj::Array<char> data) -> Orphan<Token> { [this](Location loc, kj::Array<char> data) -> Orphan<Token> {
auto t = orphanage.newOrphan<Token>(); auto t = orphanage.newOrphan<Token>();
kj::ArrayPtr<byte> dataPtr(reinterpret_cast<byte*>(data.begin()), reinterpret_cast<byte*>(data.end())); kj::ArrayPtr<byte> dataPtr(reinterpret_cast<byte*>(data.begin()),
reinterpret_cast<byte*>(data.end()));
initTok(t, loc).setBinaryLiteral(dataPtr); initTok(t, loc).setBinaryLiteral(dataPtr);
return t; return t;
}), }),
......
This diff is collapsed.
This diff is collapsed.
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <capnp/schema.capnp.h> #include <capnp/schema.capnp.h>
#include <capnp/dynamic.h> #include <capnp/dynamic.h>
#include <kj/vector.h> #include <kj/vector.h>
#include <kj/one-of.h>
#include "error-reporter.h" #include "error-reporter.h"
namespace capnp { namespace capnp {
...@@ -42,15 +43,39 @@ public: ...@@ -42,15 +43,39 @@ public:
// Callback class used to find other nodes relative to this one. // Callback class used to find other nodes relative to this one.
public: public:
struct ResolvedName { struct ResolvedDecl {
uint64_t id; uint64_t id;
uint genericParamCount;
uint64_t scopeId;
Declaration::Which kind; Declaration::Which kind;
Resolver* resolver;
}; };
virtual kj::Maybe<ResolvedName> resolve(const DeclName::Reader& name) = 0; struct ResolvedParameter {
uint64_t id; // ID of the node declaring the parameter.
uint index; // Index of the parameter.
};
struct ResolvedAlias {
Expression::Reader value;
uint64_t scopeId;
Resolver* scope;
// TODO(now): Returning an Expression from some other file is wrong wrong wrong. We need
// to compile the alias down to an id + type environment.
};
virtual kj::Maybe<kj::OneOf<ResolvedDecl, ResolvedParameter, ResolvedAlias>>
resolve(kj::StringPtr name) = 0;
// Look up the given name, relative to this node, and return basic information about the // Look up the given name, relative to this node, and return basic information about the
// target. // target.
virtual kj::Maybe<kj::OneOf<ResolvedDecl, ResolvedAlias>> resolveMember(kj::StringPtr name) = 0;
// Look up a member of this node.
virtual ResolvedDecl getTopScope() = 0;
// Get the top-level scope containing this node.
virtual kj::Maybe<Schema> resolveBootstrapSchema(uint64_t id) = 0; virtual kj::Maybe<Schema> resolveBootstrapSchema(uint64_t id) = 0;
// Get the schema for the given ID. If a schema is returned, it must be safe to traverse its // Get the schema for the given ID. If a schema is returned, it must be safe to traverse its
// dependencies using Schema::getDependency(). A schema that is only at the bootstrap stage // dependencies using Schema::getDependency(). A schema that is only at the bootstrap stage
...@@ -70,7 +95,7 @@ public: ...@@ -70,7 +95,7 @@ public:
// traversing other schemas. Returns null if the ID is recognized, but the corresponding // traversing other schemas. Returns null if the ID is recognized, but the corresponding
// schema node failed to be built for reasons that were already reported. // schema node failed to be built for reasons that were already reported.
virtual kj::Maybe<uint64_t> resolveImport(kj::StringPtr name) = 0; virtual kj::Maybe<ResolvedDecl> resolveImport(kj::StringPtr name) = 0;
// Get the ID of an imported file given the import path. // Get the ID of an imported file given the import path.
}; };
...@@ -121,7 +146,7 @@ private: ...@@ -121,7 +146,7 @@ private:
// If this is an interface, these are the auto-generated structs representing params and results. // If this is an interface, these are the auto-generated structs representing params and results.
struct UnfinishedValue { struct UnfinishedValue {
ValueExpression::Reader source; Expression::Reader source;
schema::Type::Reader type; schema::Type::Reader type;
schema::Value::Builder target; schema::Value::Builder target;
}; };
...@@ -141,6 +166,8 @@ private: ...@@ -141,6 +166,8 @@ private:
class DuplicateOrdinalDetector; class DuplicateOrdinalDetector;
class StructLayout; class StructLayout;
class StructTranslator; class StructTranslator;
class DeclInstance;
class TypeEnvironment;
void compileEnum(Void decl, List<Declaration>::Reader members, void compileEnum(Void decl, List<Declaration>::Reader members,
schema::Node::Builder builder); schema::Node::Builder builder);
...@@ -152,27 +179,35 @@ private: ...@@ -152,27 +179,35 @@ private:
// The `members` arrays contain only members with ordinal numbers, in code order. Other members // The `members` arrays contain only members with ordinal numbers, in code order. Other members
// are handled elsewhere. // are handled elsewhere.
template <typename InitTypeEnvironmentFunc>
uint64_t compileParamList(kj::StringPtr methodName, uint16_t ordinal, bool isResults, uint64_t compileParamList(kj::StringPtr methodName, uint16_t ordinal, bool isResults,
Declaration::ParamList::Reader paramList); Declaration::ParamList::Reader paramList,
InitTypeEnvironmentFunc&& initTypeEnvironment);
// Compile a param (or result) list and return the type ID of the struct type. // Compile a param (or result) list and return the type ID of the struct type.
bool compileType(TypeExpression::Reader source, schema::Type::Builder target); kj::Maybe<DeclInstance> compileDeclExpression(Expression::Reader source);
kj::Maybe<DeclInstance> compileDeclExpression(
Expression::Reader source, kj::Own<TypeEnvironment> env, Resolver& resolver);
// Compile an expression which is expected to resolve to a declaration or type expression.
bool compileType(Expression::Reader source, schema::Type::Builder target);
bool compileType(DeclInstance& decl, schema::Type::Builder target);
// Returns false if there was a problem, in which case value expressions of this type should // Returns false if there was a problem, in which case value expressions of this type should
// not be parsed. // not be parsed.
void compileDefaultDefaultValue(schema::Type::Reader type, schema::Value::Builder target); void compileDefaultDefaultValue(schema::Type::Reader type, schema::Value::Builder target);
// Initializes `target` to contain the "default default" value for `type`. // Initializes `target` to contain the "default default" value for `type`.
void compileBootstrapValue(ValueExpression::Reader source, schema::Type::Reader type, void compileBootstrapValue(Expression::Reader source, schema::Type::Reader type,
schema::Value::Builder target); schema::Value::Builder target);
// Calls compileValue() if this value should be interpreted at bootstrap time. Otheriwse, // Calls compileValue() if this value should be interpreted at bootstrap time. Otheriwse,
// adds the value to `unfinishedValues` for later evaluation. // adds the value to `unfinishedValues` for later evaluation.
void compileValue(ValueExpression::Reader source, schema::Type::Reader type, void compileValue(Expression::Reader source, schema::Type::Reader type,
schema::Value::Builder target, bool isBootstrap); schema::Value::Builder target, bool isBootstrap);
// Interprets the value expression and initializes `target` with the result. // Interprets the value expression and initializes `target` with the result.
kj::Maybe<DynamicValue::Reader> readConstant(DeclName::Reader name, bool isBootstrap); kj::Maybe<DynamicValue::Reader> readConstant(Expression::Reader name, bool isBootstrap);
// Get the value of the given constant. May return null if some error occurs, which will already // Get the value of the given constant. May return null if some error occurs, which will already
// have been reported. // have been reported.
...@@ -190,25 +225,24 @@ public: ...@@ -190,25 +225,24 @@ public:
class Resolver { class Resolver {
public: public:
virtual kj::Maybe<Schema> resolveType(uint64_t id) = 0; virtual kj::Maybe<Schema> resolveType(uint64_t id) = 0;
virtual kj::Maybe<DynamicValue::Reader> resolveConstant(DeclName::Reader name) = 0; virtual kj::Maybe<DynamicValue::Reader> resolveConstant(Expression::Reader name) = 0;
}; };
ValueTranslator(Resolver& resolver, ErrorReporter& errorReporter, Orphanage orphanage) ValueTranslator(Resolver& resolver, ErrorReporter& errorReporter, Orphanage orphanage)
: resolver(resolver), errorReporter(errorReporter), orphanage(orphanage) {} : resolver(resolver), errorReporter(errorReporter), orphanage(orphanage) {}
kj::Maybe<Orphan<DynamicValue>> compileValue( kj::Maybe<Orphan<DynamicValue>> compileValue(Expression::Reader src, schema::Type::Reader type);
ValueExpression::Reader src, schema::Type::Reader type);
private: private:
Resolver& resolver; Resolver& resolver;
ErrorReporter& errorReporter; ErrorReporter& errorReporter;
Orphanage orphanage; Orphanage orphanage;
Orphan<DynamicValue> compileValueInner(ValueExpression::Reader src, schema::Type::Reader type); Orphan<DynamicValue> compileValueInner(Expression::Reader src, schema::Type::Reader type);
// Helper for compileValue(). // Helper for compileValue().
void fillStructValue(DynamicStruct::Builder builder, void fillStructValue(DynamicStruct::Builder builder,
List<ValueExpression::FieldAssignment>::Reader assignments); List<Expression::Param>::Reader assignments);
// Interprets the given assignments and uses them to fill in the given struct builder. // Interprets the given assignments and uses them to fill in the given struct builder.
kj::String makeNodeName(uint64_t id); kj::String makeNodeName(uint64_t id);
......
This diff is collapsed.
...@@ -111,10 +111,7 @@ public: ...@@ -111,10 +111,7 @@ public:
// enums, but they'll be accepted by enumLevelDecl. A later stage of compilation should report // enums, but they'll be accepted by enumLevelDecl. A later stage of compilation should report
// these as errors. // these as errors.
Parser<Orphan<DeclName>> declName; Parser<Orphan<Expression>> expression;
Parser<Orphan<TypeExpression>> typeExpression;
Parser<Orphan<ValueExpression>> valueExpression;
Parser<Orphan<ValueExpression>> parenthesizedValueExpression;
Parser<Orphan<Declaration::AnnotationApplication>> annotation; Parser<Orphan<Declaration::AnnotationApplication>> annotation;
Parser<Orphan<LocatedInteger>> uid; Parser<Orphan<LocatedInteger>> uid;
Parser<Orphan<LocatedInteger>> ordinal; Parser<Orphan<LocatedInteger>> ordinal;
......
This diff is collapsed.
This diff is collapsed.
...@@ -373,7 +373,7 @@ private: ...@@ -373,7 +373,7 @@ private:
void validate(const schema::Node::Interface::Reader& interfaceNode) { void validate(const schema::Node::Interface::Reader& interfaceNode) {
for (auto extend: interfaceNode.getExtends()) { for (auto extend: interfaceNode.getExtends()) {
validateTypeId(extend, schema::Node::INTERFACE); validateTypeId(extend.getId(), schema::Node::INTERFACE);
} }
auto methods = interfaceNode.getMethods(); auto methods = interfaceNode.getMethods();
...@@ -754,11 +754,11 @@ private: ...@@ -754,11 +754,11 @@ private:
kj::Vector<uint64_t> extends; kj::Vector<uint64_t> extends;
kj::Vector<uint64_t> replacementExtends; kj::Vector<uint64_t> replacementExtends;
for (uint64_t extend: interfaceNode.getExtends()) { for (auto extend: interfaceNode.getExtends()) {
extends.add(extend); extends.add(extend.getId());
} }
for (uint64_t extend: replacement.getExtends()) { for (auto extend: replacement.getExtends()) {
replacementExtends.add(extend); replacementExtends.add(extend.getId());
} }
std::sort(extends.begin(), extends.end()); std::sort(extends.begin(), extends.end());
std::sort(replacementExtends.begin(), replacementExtends.end()); std::sort(replacementExtends.begin(), replacementExtends.end());
......
...@@ -406,8 +406,8 @@ kj::Maybe<InterfaceSchema::Method> InterfaceSchema::findMethodByName( ...@@ -406,8 +406,8 @@ kj::Maybe<InterfaceSchema::Method> InterfaceSchema::findMethodByName(
// this means that a dynamically-loaded RawSchema cannot be correctly constructed until all // this means that a dynamically-loaded RawSchema cannot be correctly constructed until all
// superclasses have been loaded, which imposes an ordering requirement on SchemaLoader or // superclasses have been loaded, which imposes an ordering requirement on SchemaLoader or
// requires updating subclasses whenever a new superclass is loaded. // requires updating subclasses whenever a new superclass is loaded.
for (auto extendId: getProto().getInterface().getExtends()) { for (auto extend: getProto().getInterface().getExtends()) {
result = getDependency(extendId).asInterface().findMethodByName(name, counter); result = getDependency(extend.getId()).asInterface().findMethodByName(name, counter);
if (result != nullptr) { if (result != nullptr) {
break; break;
} }
...@@ -445,8 +445,8 @@ bool InterfaceSchema::extends(InterfaceSchema other, uint& counter) const { ...@@ -445,8 +445,8 @@ bool InterfaceSchema::extends(InterfaceSchema other, uint& counter) const {
} }
// TODO(perf): This may be somewhat slow. See findMethodByName() for discussion. // TODO(perf): This may be somewhat slow. See findMethodByName() for discussion.
for (auto extendId: getProto().getInterface().getExtends()) { for (auto extend: getProto().getInterface().getExtends()) {
if (getDependency(extendId).asInterface().extends(other, counter)) { if (getDependency(extend.getId()).asInterface().extends(other, counter)) {
return true; return true;
} }
} }
...@@ -474,8 +474,9 @@ kj::Maybe<InterfaceSchema> InterfaceSchema::findSuperclass(uint64_t typeId, uint ...@@ -474,8 +474,9 @@ kj::Maybe<InterfaceSchema> InterfaceSchema::findSuperclass(uint64_t typeId, uint
} }
// TODO(perf): This may be somewhat slow. See findMethodByName() for discussion. // TODO(perf): This may be somewhat slow. See findMethodByName() for discussion.
for (auto extendId: getProto().getInterface().getExtends()) { for (auto extend: getProto().getInterface().getExtends()) {
KJ_IF_MAYBE(result, getDependency(extendId).asInterface().findSuperclass(typeId, counter)) { KJ_IF_MAYBE(result, getDependency(extend.getId()).asInterface()
.findSuperclass(typeId, counter)) {
return *result; return *result;
} }
} }
......
...@@ -47,6 +47,15 @@ struct Node { ...@@ -47,6 +47,15 @@ struct Node {
# zero if the node has no parent, which is normally only the case with files, but should be # zero if the node has no parent, which is normally only the case with files, but should be
# allowed for any kind of node (in order to make runtime type generation easier). # allowed for any kind of node (in order to make runtime type generation easier).
parameters @32 :List(Parameter);
# If this node is parameterized (generic), the list of parameters. Empty for non-generic types.
struct Parameter {
# Information about one of the node's parameters.
name @0 :Text;
}
nestedNodes @4 :List(NestedNode); nestedNodes @4 :List(NestedNode);
# List of nodes nested within this node, along with the names under which they were declared. # List of nodes nested within this node, along with the names under which they were declared.
...@@ -130,7 +139,7 @@ struct Node { ...@@ -130,7 +139,7 @@ struct Node {
methods @15 :List(Method); methods @15 :List(Method);
# Methods ordered by ordinal. # Methods ordered by ordinal.
extends @31 :List(Id); extends @31 :List(Extend);
# Superclasses of this interface. # Superclasses of this interface.
} }
...@@ -156,6 +165,11 @@ struct Node { ...@@ -156,6 +165,11 @@ struct Node {
targetsAnnotation @30 :Bool; targetsAnnotation @30 :Bool;
} }
} }
struct Extend {
id @0 :Id;
environment @1 :TypeEnvironment;
}
} }
struct Field { struct Field {
...@@ -242,10 +256,19 @@ struct Method { ...@@ -242,10 +256,19 @@ struct Method {
# declaration (rather than a single struct parameter type) then a corresponding struct type is # declaration (rather than a single struct parameter type) then a corresponding struct type is
# auto-generated. Such an auto-generated type will not be listed in the interface's # auto-generated. Such an auto-generated type will not be listed in the interface's
# `nestedNodes` and its `scopeId` will be zero -- it is completely detached from the namespace. # `nestedNodes` and its `scopeId` will be zero -- it is completely detached from the namespace.
# (Awkwardly, it does of course inherit generic parameters from the method's scope, which makes
# this a situation where you can't just climb the scope chain to find where a particular
# generic parameter was introduced. Making the `scopeId` zero was a mistake.)
paramEnvironment @5 :TypeEnvironment;
# Parameterization of param struct type.
resultStructType @3 :Id; resultStructType @3 :Id;
# ID of the return struct type; similar to `paramStructType`. # ID of the return struct type; similar to `paramStructType`.
resultEnvironment @6 :TypeEnvironment;
# Parameterization of result struct type.
annotations @4 :List(Annotation); annotations @4 :List(Annotation);
} }
...@@ -276,15 +299,60 @@ struct Type { ...@@ -276,15 +299,60 @@ struct Type {
enum :group { enum :group {
typeId @15 :Id; typeId @15 :Id;
typeEnvironment @21 :TypeEnvironment;
} }
struct :group { struct :group {
typeId @16 :Id; typeId @16 :Id;
typeEnvironment @22 :TypeEnvironment;
} }
interface :group { interface :group {
typeId @17 :Id; typeId @17 :Id;
typeEnvironment @23 :TypeEnvironment;
} }
anyPointer @18 :Void; anyPointer :union {
unconstrained @18 :Void;
# A regular AnyPointer.
parameter :group {
# This is actually a reference to a type parameter defined within this scope.
nodeId @19 :Id;
# Node ID of the generic type whose parameter we're referencing. This must be a parent
# of the current scope.
parameterIndex @20 :UInt16;
# Index of the parameter within the generic type's parameter list.
}
}
}
}
struct TypeEnvironment {
# Specifies type parameters applying to a target type declaration, i.e. for generic types.
scopes @0 :List(Scope);
# For each of the target type and each of its parent scopes, a parameterization may be included
# in this list. If no parameterization is included for a particular relevant scope, then either
# that scope has no parameters or all parameters should be considered to be `AnyPointer`.
#
# TODO(now): improve naming
struct Scope {
scopeId @0 :Id;
# ID of the scope to which these params apply.
bindings @1 :List(Binding);
# List of parameter bindings.
}
struct Binding {
union {
unbound @0 :Void;
type @1 :Type;
# TODO(someday): Allow non-type parameters? Unsure if useful.
}
} }
} }
...@@ -329,6 +397,11 @@ struct Annotation { ...@@ -329,6 +397,11 @@ struct Annotation {
id @0 :Id; id @0 :Id;
# ID of the annotation node. # ID of the annotation node.
typeEnvironment @2 :TypeEnvironment;
# Type environment of the annotation.
#
# Note that the annotation itself is not allowed to be parameterized, but its scope might be.
value @1 :Value; value @1 :Value;
} }
......
This diff is collapsed.
This diff is collapsed.
...@@ -141,7 +141,7 @@ static kj::StringTree print(const DynamicValue::Reader& value, ...@@ -141,7 +141,7 @@ static kj::StringTree print(const DynamicValue::Reader& value,
} }
case DynamicValue::TEXT: case DynamicValue::TEXT:
case DynamicValue::DATA: { case DynamicValue::DATA: {
// TODO(someday): Data probably shouldn't be printed as a string. // TODO(now): Data should be printed as binary literal.
kj::ArrayPtr<const char> chars; kj::ArrayPtr<const char> chars;
if (value.getType() == DynamicValue::DATA) { if (value.getType() == DynamicValue::DATA) {
auto reader = value.as<Data>(); auto reader = value.as<Data>();
......
...@@ -503,6 +503,33 @@ struct TestWholeFloatDefault { ...@@ -503,6 +503,33 @@ struct TestWholeFloatDefault {
const bigConstant :Float32 = 4e30; const bigConstant :Float32 = 4e30;
} }
struct TestGenerics(Foo, Bar) {
foo @0 :Foo;
rev @1 :TestGenerics(Bar, Foo);
struct Inner {
foo @0 :Foo;
bar @1 :Bar;
}
struct Inner2(Baz) {
bar @0 :Bar;
baz @1 :Baz;
}
interface Interface(Qux) {
call @0 Inner2(Text) -> (qux :Qux, gen :TestGenerics(TestAllTypes, TestDefaults));
}
}
struct TestUseGenerics {
basic @0 :TestGenerics(TestAllTypes, TestDefaults);
inner @1 :TestGenerics(TestAllTypes, TestDefaults).Inner;
inner2 @2 :TestGenerics(TestAllTypes, TestDefaults).Inner2(Text);
unspecified @3 :TestGenerics;
unspecifiedInner @4 :TestGenerics.Inner2(Text);
}
struct TestEmptyStruct {} struct TestEmptyStruct {}
struct TestConstants { struct TestConstants {
......
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