Commit d7b612a1 authored by Kenton Varda's avatar Kenton Varda

Generics: Schema parser.

parent 4023a354
......@@ -5,17 +5,18 @@
namespace capnp {
namespace schemas {
static const ::capnp::_::AlignedData<19> b_b9c6f99ebf805f2c = {
{ 0, 0, 0, 0, 5, 0, 5, 0,
static const ::capnp::_::AlignedData<21> b_b9c6f99ebf805f2c = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
44, 95, 128, 191, 158, 249, 198, 185,
16, 0, 0, 0, 5, 0, 1, 0,
129, 78, 48, 184, 123, 125, 248, 189,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
17, 0, 0, 0, 210, 0, 0, 0,
29, 0, 0, 0, 7, 0, 0, 0,
21, 0, 0, 0, 210, 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,
24, 0, 0, 0, 2, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0,
99, 97, 112, 110, 112, 47, 99, 43,
43, 46, 99, 97, 112, 110, 112, 58,
......@@ -23,35 +24,38 @@ static const ::capnp::_::AlignedData<19> b_b9c6f99ebf805f2c = {
101, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 1, 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, }
};
const ::capnp::_::RawSchema s_b9c6f99ebf805f2c = {
0xb9c6f99ebf805f2c, b_b9c6f99ebf805f2c.words, 19, nullptr, nullptr,
0xb9c6f99ebf805f2c, b_b9c6f99ebf805f2c.words, 21, nullptr, nullptr,
0, 0, nullptr, nullptr, nullptr
};
static const ::capnp::_::AlignedData<18> b_f264a779fef191ce = {
{ 0, 0, 0, 0, 5, 0, 5, 0,
static const ::capnp::_::AlignedData<20> b_f264a779fef191ce = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
206, 145, 241, 254, 121, 167, 100, 242,
16, 0, 0, 0, 5, 0, 252, 7,
129, 78, 48, 184, 123, 125, 248, 189,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
17, 0, 0, 0, 170, 0, 0, 0,
25, 0, 0, 0, 7, 0, 0, 0,
21, 0, 0, 0, 170, 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,
20, 0, 0, 0, 2, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0,
99, 97, 112, 110, 112, 47, 99, 43,
43, 46, 99, 97, 112, 110, 112, 58,
110, 97, 109, 101, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 1, 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, }
};
const ::capnp::_::RawSchema s_f264a779fef191ce = {
0xf264a779fef191ce, b_f264a779fef191ce.words, 18, nullptr, nullptr,
0xf264a779fef191ce, b_f264a779fef191ce.words, 20, nullptr, nullptr,
0, 0, nullptr, nullptr, nullptr
};
} // namespace schemas
......
......@@ -1013,7 +1013,7 @@ public:
kj::BufferedOutputStreamWrapper output(rawOutput);
while (parserInput.getPosition() != tokens.end()) {
KJ_IF_MAYBE(expression, parser.getParsers().parenthesizedValueExpression(parserInput)) {
KJ_IF_MAYBE(expression, parser.getParsers().expression(parserInput)) {
MallocMessageBuilder item(
segmentSize == 0 ? SUGGESTED_FIRST_SEGMENT_WORDS : segmentSize,
segmentSize == 0 ? SUGGESTED_ALLOCATION_STRATEGY : AllocationStrategy::FIXED_SIZE);
......@@ -1243,25 +1243,8 @@ private:
return loader.get(id);
}
kj::Maybe<DynamicValue::Reader> resolveConstant(DeclName::Reader name) {
auto base = name.getBase();
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;
}
}
kj::Maybe<DynamicValue::Reader> resolveConstant(Expression::Reader name) {
errorReporter.addErrorOn(name, kj::str("External constants not allowed in encode input."));
return nullptr;
}
......
......@@ -103,7 +103,7 @@ void enumerateDeps(schema::Node::Reader node, std::set<uint64_t>& deps) {
case schema::Node::INTERFACE: {
auto interfaceNode = node.getInterface();
for (auto extend: interfaceNode.getExtends()) {
deps.insert(extend);
deps.insert(extend.getId());
}
for (auto method: interfaceNode.getMethods()) {
deps.insert(method.getParamStructType());
......@@ -1327,8 +1327,8 @@ private:
auto proto = schema.getProto();
auto extends = KJ_MAP(id, proto.getInterface().getExtends()) {
Schema schema = schemaLoader.get(id);
auto extends = KJ_MAP(extend, proto.getInterface().getExtends()) {
Schema schema = schemaLoader.get(extend.getId());
return ExtendInfo { cppFullName(schema).flatten(), schema.getProto().getId() };
};
......
......@@ -34,6 +34,7 @@
#include <unordered_map>
#include <kj/main.h>
#include <algorithm>
#include <map>
#if HAVE_CONFIG_H
#include "config.h"
......@@ -113,15 +114,22 @@ private:
return "(?)";
}
kj::StringTree nodeName(Schema target, Schema scope) {
kj::Vector<Schema> targetParents;
kj::StringTree nodeName(Schema target, Schema scope, schema::TypeEnvironment::Reader env) {
kj::Vector<Schema> targetPath;
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;
while (parent.getProto().getScopeId() != 0) {
parent = schemaLoader.get(parent.getProto().getScopeId());
targetParents.add(parent);
targetPath.add(parent);
}
}
......@@ -134,28 +142,45 @@ private:
}
}
// Remove common scope.
while (!scopeParts.empty() && !targetParents.empty() &&
scopeParts.back() == targetParents.back()) {
// Remove common scope (unless it has been reparameterized).
// TODO(someday): This is broken in that we aren't checking for shadowing.
while (!scopeParts.empty() && targetPath.size() > 1 &&
scopeParts.back() == targetPath.back() &&
scopeBindings.count(scopeParts.back().getProto().getId()) == 0) {
scopeParts.removeLast();
targetParents.removeLast();
targetPath.removeLast();
}
// TODO(someday): This is broken in that we aren't checking for shadowing.
kj::StringTree path = kj::strTree();
while (!targetParents.empty()) {
auto part = targetParents.back();
auto parts = kj::heapArrayBuilder<kj::StringTree>(targetPath.size());
while (!targetPath.empty()) {
auto part = targetPath.back();
auto proto = part.getProto();
kj::StringTree partStr;
if (proto.getScopeId() == 0) {
path = kj::strTree(kj::mv(path), "import \"/", proto.getDisplayName(), "\".");
partStr = kj::strTree("import \"/", proto.getDisplayName(), '\"');
} 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) {
......@@ -177,12 +202,33 @@ private:
case schema::Type::LIST:
return kj::strTree("List(", genType(type.getList().getElementType(), scope), ")");
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:
return nodeName(schemaLoader.get(type.getStruct().getTypeId()), scope);
return nodeName(schemaLoader.get(type.getStruct().getTypeId()), scope,
type.getStruct().getTypeEnvironment());
case schema::Type::INTERFACE:
return nodeName(schemaLoader.get(type.getInterface().getTypeId()), scope);
case schema::Type::ANY_POINTER: return kj::strTree("AnyPointer");
return nodeName(schemaLoader.get(type.getInterface().getTypeId()), scope,
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();
}
......@@ -286,6 +332,19 @@ private:
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,
Schema scope,
const char* prefix = " ", const char* suffix = "") {
......@@ -296,9 +355,11 @@ private:
auto value = genValue(annDecl.getType(), annotation.getValue(), decl).flatten();
if (value.startsWith("(")) {
return kj::strTree(prefix, "$", nodeName(decl, scope), value, suffix);
return kj::strTree(prefix, "$", nodeName(decl, scope, annotation.getTypeEnvironment()),
value, suffix);
} 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:
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) {
// A named parameter list.
return kj::strTree("(", kj::StringTree(
......@@ -418,7 +480,7 @@ private:
genAnnotations(proto.getAnnotations(), interface));
}, ", "), ")");
} else {
return nodeName(schema, interface);
return nodeName(schema, interface, env);
}
}
......@@ -428,8 +490,9 @@ private:
return kj::strTree();
} else {
return kj::strTree(" extends(", kj::StringTree(
KJ_MAP(id, extends) {
return nodeName(schemaLoader.get(id), interface);
KJ_MAP(extend, extends) {
return nodeName(schemaLoader.get(extend.getId()), interface,
extend.getEnvironment());
}, ", "), ")");
}
}
......@@ -449,7 +512,8 @@ private:
auto structProto = proto.getStruct();
return kj::strTree(
indent, "struct ", name,
" @0x", kj::hex(proto.getId()), genAnnotations(schema), " { # ",
" @0x", kj::hex(proto.getId()), genGenericParams(schema),
genAnnotations(schema), " { # ",
structProto.getDataWordCount() * 8, " bytes, ",
structProto.getPointerCount(), " ptrs",
structProto.getPreferredListEncoding() == schema::ElementSize::INLINE_COMPOSITE
......@@ -475,7 +539,7 @@ private:
case schema::Node::INTERFACE: {
auto interface = schema.asInterface();
return kj::strTree(
indent, "interface ", name, " @0x", kj::hex(proto.getId()),
indent, "interface ", name, " @0x", kj::hex(proto.getId()), genGenericParams(schema),
genExtends(interface),
genAnnotations(schema), " {\n",
KJ_MAP(method, sortByCodeOrder(interface.getMethods())) {
......@@ -484,7 +548,8 @@ private:
auto results = schemaLoader.get(methodProto.getResultStructType()).asStruct();
return kj::strTree(
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");
},
genNestedDecls(schema, indent.next()),
......
This diff is collapsed.
......@@ -73,64 +73,64 @@ static Declaration::Builder addNested(Declaration::Builder parent) {
struct TypeOption {
kj::StringPtr name;
kj::ConstFunction<void(ValueExpression::Builder)> makeValue;
kj::ConstFunction<void(Expression::Builder)> makeValue;
};
static const TypeOption TYPE_OPTIONS[] = {
{ "Int32",
[](ValueExpression::Builder builder) {
[](Expression::Builder builder) {
builder.setPositiveInt(rand() % (1 << 24));
}},
{ "Float64",
[](ValueExpression::Builder builder) {
[](Expression::Builder builder) {
builder.setPositiveInt(rand());
}},
{ "Int8",
[](ValueExpression::Builder builder) {
[](Expression::Builder builder) {
builder.setPositiveInt(rand() % 128);
}},
{ "UInt16",
[](ValueExpression::Builder builder) {
[](Expression::Builder builder) {
builder.setPositiveInt(rand() % (1 << 16));
}},
{ "Bool",
[](ValueExpression::Builder builder) {
builder.initName().getBase().initRelativeName().setValue("true");
[](Expression::Builder builder) {
builder.initRelativeName().setValue("true");
}},
{ "Text",
[](ValueExpression::Builder builder) {
[](Expression::Builder builder) {
builder.setString(chooseFrom(RFC3092));
}},
{ "StructType",
[](ValueExpression::Builder builder) {
auto assignment = builder.initStruct(1)[0];
assignment.initFieldName().setValue("i");
[](Expression::Builder builder) {
auto assignment = builder.initTuple(1)[0];
assignment.initNamed().setValue("i");
assignment.initValue().setPositiveInt(rand() % (1 << 24));
}},
{ "EnumType",
[](ValueExpression::Builder builder) {
builder.initName().getBase().initRelativeName().setValue(chooseFrom(RFC3092));
[](Expression::Builder builder) {
builder.initRelativeName().setValue(chooseFrom(RFC3092));
}},
};
void setDeclName(DeclName::Builder decl, kj::StringPtr name) {
decl.getBase().initRelativeName().setValue(name);
void setDeclName(Expression::Builder decl, kj::StringPtr name) {
decl.initRelativeName().setValue(name);
}
static kj::ConstFunction<void(ValueExpression::Builder)> randomizeType(
TypeExpression::Builder type) {
static kj::ConstFunction<void(Expression::Builder)> randomizeType(Expression::Builder type) {
auto option = &chooseFrom(TYPE_OPTIONS);
if (rand() % 4 == 0) {
setDeclName(type.initName(), "List");
setDeclName(type.initParams(1)[0].initName(), option->name);
return [option](ValueExpression::Builder builder) {
auto app = type.initApplication();
setDeclName(app.initFunction(), "List");
setDeclName(app.initParams(1)[0].initValue(), option->name);
return [option](Expression::Builder builder) {
for (auto element: builder.initList(rand() % 4 + 1)) {
option->makeValue(element);
}
};
} else {
setDeclName(type.initName(), option->name);
setDeclName(type, option->name);
return option->makeValue.reference();
}
}
......@@ -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." };
}
auto typeParams = field.getType().getParams();
if (typeParams.size() != 1) {
auto type = field.getType();
if (!type.isApplication()) {
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 relativeName = elementType.getName().getBase().getRelativeName();
auto elementType = typeParams[0].getValue();
auto relativeName = elementType.getRelativeName();
auto nameText = relativeName.asReader().getValue();
if (nameText == "StructType" || nameText.endsWith("Struct")) {
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,
if (field.getDefaultValue().isNone()) {
// Change the type.
auto type = field.getType();
while (type.getParams().size() > 0) {
while (type.isApplication()) {
// Either change the list parameter, or revert to a non-list.
if (rand() % 2) {
type = type.getParams()[0];
type = type.getApplication().getParams()[0].getValue();
} else {
type.disownParams();
type.initRelativeName();
}
}
auto typeName = type.getName().getBase().getRelativeName();
auto typeName = type.getRelativeName();
if (typeName.asReader().getValue().startsWith("Text")) {
typeName.setValue("Int32");
} else {
......@@ -399,12 +400,12 @@ static ChangeInfo fieldChangeType(Declaration::Builder decl, uint& nextOrdinal,
// Change the default value.
auto dval = field.getDefaultValue().getValue();
switch (dval.which()) {
case ValueExpression::UNKNOWN: KJ_FAIL_ASSERT("unknown value expression?");
case ValueExpression::POSITIVE_INT: dval.setPositiveInt(dval.getPositiveInt() ^ 1); break;
case ValueExpression::NEGATIVE_INT: dval.setNegativeInt(dval.getNegativeInt() ^ 1); break;
case ValueExpression::FLOAT: dval.setFloat(-dval.getFloat()); break;
case ValueExpression::NAME: {
auto name = dval.getName().getBase().getRelativeName();
case Expression::UNKNOWN: KJ_FAIL_ASSERT("unknown value expression?");
case Expression::POSITIVE_INT: dval.setPositiveInt(dval.getPositiveInt() ^ 1); break;
case Expression::NEGATIVE_INT: dval.setNegativeInt(dval.getNegativeInt() ^ 1); break;
case Expression::FLOAT: dval.setFloat(-dval.getFloat()); break;
case Expression::RELATIVE_NAME: {
auto name = dval.getRelativeName();
auto nameText = name.asReader().getValue();
if (nameText == "true") {
name.setValue("false");
......@@ -417,10 +418,17 @@ static ChangeInfo fieldChangeType(Declaration::Builder decl, uint& nextOrdinal,
}
break;
}
case ValueExpression::STRING:
case ValueExpression::LIST:
case ValueExpression::STRUCT:
case Expression::STRING:
case Expression::BINARY:
case Expression::LIST:
case Expression::TUPLE:
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." };
}
......@@ -764,7 +772,7 @@ void doTest() {
fieldDecl.initName().setValue("i");
fieldDecl.getId().initOrdinal().setValue(0);
auto field = fieldDecl.initField();
setDeclName(field.initType().initName(), "UInt32");
setDeclName(field.initType(), "UInt32");
}
{
auto decl = decls[2];
......@@ -793,7 +801,7 @@ void doTest() {
fieldDecl.initName().setValue("f0");
fieldDecl.getId().initOrdinal().setValue(0);
auto field = fieldDecl.initField();
setDeclName(field.initType().initName(), option.name);
setDeclName(field.initType(), option.name);
uint ordinal = 1;
for (auto j: kj::range(0, rand() % 4)) {
......
......@@ -50,45 +50,9 @@ struct LocatedFloat {
endByte @2 :UInt32;
}
struct DeclName {
# An expressing naming a thing declared elsewhere. Examples:
# * `MyType`
# * `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.
struct Expression {
# An expression. May evaluate to a type, a value, or a declaration (i.e. some named thing which
# is neither a type nor a value, like an annotation declaration).
union {
unknown @0 :Void; # e.g. parse error; downstream should ignore
......@@ -97,14 +61,48 @@ struct ValueExpression {
float @3 :Float64;
string @4 :Text;
binary @10 :Data;
name @5 :DeclName;
list @6 :List(ValueExpression);
struct @7 :List(FieldAssignment);
relativeName @5 :LocatedText;
# 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 {
fieldName @0 :LocatedText;
value @1 :ValueExpression;
struct Param {
union {
unnamed @0 :Void; # Just a value.
named @1 :LocatedText; # "name = value"
}
value @2 :Expression;
}
startByte @8 :UInt32;
......@@ -122,15 +120,24 @@ struct Declaration {
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);
annotations @5 :List(AnnotationApplication);
struct AnnotationApplication {
name @0 :DeclName;
name @0 :Expression;
value :union {
none @1 :Void; # None specified; implies void value.
expression @2 :ValueExpression;
expression @2 :Expression;
}
}
......@@ -143,12 +150,12 @@ struct Declaration {
file @9 :Void;
using :group {
target @10 :DeclName;
target @10 :Expression;
}
const :group {
type @11 :TypeExpression;
value @12 :ValueExpression;
type @11 :Expression;
value @12 :Expression;
}
enum @13 :Void;
......@@ -156,17 +163,17 @@ struct Declaration {
struct @15 :Void;
field :group {
type @16 :TypeExpression;
type @16 :Expression;
defaultValue :union {
none @17 :Void;
value @18 :ValueExpression;
value @18 :Expression;
}
}
union @19 :Void;
group @20 :Void;
interface :group {
extends @21 :List(DeclName);
extends @21 :List(Expression);
}
method :group {
params @22 :ParamList;
......@@ -177,7 +184,7 @@ struct Declaration {
}
annotation :group {
type @25 :TypeExpression;
type @25 :Expression;
targetsFile @26 :Bool;
targetsConst @27 :Bool;
......@@ -216,18 +223,20 @@ struct Declaration {
builtinFloat64 @51 :Void;
builtinText @52 :Void;
builtinData @53 :Void;
builtinList @54 :Void;
builtinList @54 :Void $builtinParams([(name = "Element")]);
builtinObject @55 :Void; # only for "renamed to AnyPointer" error message
builtinAnyPointer @56 :Void;
}
annotation builtinParams @0x94099c3f9eb32d6b (field) :List(TypeParameter);
struct ParamList {
# A list of method parameters or method returns.
union {
namedList @0 :List(Param);
type @1 :DeclName;
type @1 :Expression;
# Specified some other struct type instead of a named list.
}
......@@ -236,11 +245,11 @@ struct Declaration {
}
struct Param {
name @0 :LocatedText; # If null, param failed to parse.
type @1 :TypeExpression;
type @1 :Expression;
annotations @2 :List(AnnotationApplication);
defaultValue :union {
none @3 :Void;
value @4 :ValueExpression;
value @4 :Expression;
}
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)
p::transformWithLocation(p::doubleQuotedHexBinary,
[this](Location loc, kj::Array<char> data) -> Orphan<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);
return t;
}),
......
This diff is collapsed.
This diff is collapsed.
......@@ -27,6 +27,7 @@
#include <capnp/schema.capnp.h>
#include <capnp/dynamic.h>
#include <kj/vector.h>
#include <kj/one-of.h>
#include "error-reporter.h"
namespace capnp {
......@@ -42,15 +43,39 @@ public:
// Callback class used to find other nodes relative to this one.
public:
struct ResolvedName {
struct ResolvedDecl {
uint64_t id;
uint genericParamCount;
uint64_t scopeId;
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
// 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;
// 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
......@@ -70,7 +95,7 @@ public:
// traversing other schemas. Returns null if the ID is recognized, but the corresponding
// schema node failed to be built for reasons that were already reported.
virtual 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.
};
......@@ -121,7 +146,7 @@ private:
// If this is an interface, these are the auto-generated structs representing params and results.
struct UnfinishedValue {
ValueExpression::Reader source;
Expression::Reader source;
schema::Type::Reader type;
schema::Value::Builder target;
};
......@@ -141,6 +166,8 @@ private:
class DuplicateOrdinalDetector;
class StructLayout;
class StructTranslator;
class DeclInstance;
class TypeEnvironment;
void compileEnum(Void decl, List<Declaration>::Reader members,
schema::Node::Builder builder);
......@@ -152,27 +179,35 @@ private:
// The `members` arrays contain only members with ordinal numbers, in code order. Other members
// are handled elsewhere.
template <typename InitTypeEnvironmentFunc>
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.
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
// not be parsed.
void compileDefaultDefaultValue(schema::Type::Reader type, schema::Value::Builder target);
// 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);
// Calls compileValue() if this value should be interpreted at bootstrap time. Otheriwse,
// 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);
// 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
// have been reported.
......@@ -190,25 +225,24 @@ public:
class Resolver {
public:
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)
: resolver(resolver), errorReporter(errorReporter), orphanage(orphanage) {}
kj::Maybe<Orphan<DynamicValue>> compileValue(
ValueExpression::Reader src, schema::Type::Reader type);
kj::Maybe<Orphan<DynamicValue>> compileValue(Expression::Reader src, schema::Type::Reader type);
private:
Resolver& resolver;
ErrorReporter& errorReporter;
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().
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.
kj::String makeNodeName(uint64_t id);
......
This diff is collapsed.
......@@ -111,10 +111,7 @@ public:
// enums, but they'll be accepted by enumLevelDecl. A later stage of compilation should report
// these as errors.
Parser<Orphan<DeclName>> declName;
Parser<Orphan<TypeExpression>> typeExpression;
Parser<Orphan<ValueExpression>> valueExpression;
Parser<Orphan<ValueExpression>> parenthesizedValueExpression;
Parser<Orphan<Expression>> expression;
Parser<Orphan<Declaration::AnnotationApplication>> annotation;
Parser<Orphan<LocatedInteger>> uid;
Parser<Orphan<LocatedInteger>> ordinal;
......
This diff is collapsed.
This diff is collapsed.
......@@ -373,7 +373,7 @@ private:
void validate(const schema::Node::Interface::Reader& interfaceNode) {
for (auto extend: interfaceNode.getExtends()) {
validateTypeId(extend, schema::Node::INTERFACE);
validateTypeId(extend.getId(), schema::Node::INTERFACE);
}
auto methods = interfaceNode.getMethods();
......@@ -754,11 +754,11 @@ private:
kj::Vector<uint64_t> extends;
kj::Vector<uint64_t> replacementExtends;
for (uint64_t extend: interfaceNode.getExtends()) {
extends.add(extend);
for (auto extend: interfaceNode.getExtends()) {
extends.add(extend.getId());
}
for (uint64_t extend: replacement.getExtends()) {
replacementExtends.add(extend);
for (auto extend: replacement.getExtends()) {
replacementExtends.add(extend.getId());
}
std::sort(extends.begin(), extends.end());
std::sort(replacementExtends.begin(), replacementExtends.end());
......
......@@ -406,8 +406,8 @@ kj::Maybe<InterfaceSchema::Method> InterfaceSchema::findMethodByName(
// 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
// requires updating subclasses whenever a new superclass is loaded.
for (auto extendId: getProto().getInterface().getExtends()) {
result = getDependency(extendId).asInterface().findMethodByName(name, counter);
for (auto extend: getProto().getInterface().getExtends()) {
result = getDependency(extend.getId()).asInterface().findMethodByName(name, counter);
if (result != nullptr) {
break;
}
......@@ -445,8 +445,8 @@ bool InterfaceSchema::extends(InterfaceSchema other, uint& counter) const {
}
// TODO(perf): This may be somewhat slow. See findMethodByName() for discussion.
for (auto extendId: getProto().getInterface().getExtends()) {
if (getDependency(extendId).asInterface().extends(other, counter)) {
for (auto extend: getProto().getInterface().getExtends()) {
if (getDependency(extend.getId()).asInterface().extends(other, counter)) {
return true;
}
}
......@@ -474,8 +474,9 @@ kj::Maybe<InterfaceSchema> InterfaceSchema::findSuperclass(uint64_t typeId, uint
}
// TODO(perf): This may be somewhat slow. See findMethodByName() for discussion.
for (auto extendId: getProto().getInterface().getExtends()) {
KJ_IF_MAYBE(result, getDependency(extendId).asInterface().findSuperclass(typeId, counter)) {
for (auto extend: getProto().getInterface().getExtends()) {
KJ_IF_MAYBE(result, getDependency(extend.getId()).asInterface()
.findSuperclass(typeId, counter)) {
return *result;
}
}
......
......@@ -47,6 +47,15 @@ struct Node {
# 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).
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);
# List of nodes nested within this node, along with the names under which they were declared.
......@@ -130,7 +139,7 @@ struct Node {
methods @15 :List(Method);
# Methods ordered by ordinal.
extends @31 :List(Id);
extends @31 :List(Extend);
# Superclasses of this interface.
}
......@@ -156,6 +165,11 @@ struct Node {
targetsAnnotation @30 :Bool;
}
}
struct Extend {
id @0 :Id;
environment @1 :TypeEnvironment;
}
}
struct Field {
......@@ -242,10 +256,19 @@ struct Method {
# 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
# `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;
# ID of the return struct type; similar to `paramStructType`.
resultEnvironment @6 :TypeEnvironment;
# Parameterization of result struct type.
annotations @4 :List(Annotation);
}
......@@ -276,15 +299,60 @@ struct Type {
enum :group {
typeId @15 :Id;
typeEnvironment @21 :TypeEnvironment;
}
struct :group {
typeId @16 :Id;
typeEnvironment @22 :TypeEnvironment;
}
interface :group {
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 {
id @0 :Id;
# 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;
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -141,7 +141,7 @@ static kj::StringTree print(const DynamicValue::Reader& value,
}
case DynamicValue::TEXT:
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;
if (value.getType() == DynamicValue::DATA) {
auto reader = value.as<Data>();
......
......@@ -503,6 +503,33 @@ struct TestWholeFloatDefault {
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 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