Commit 24b27eae authored by Eric Myhre's avatar Eric Myhre

Self-hosting gen of the schema-schema.

... With a few minor alterations.

I've taken the opportunity to make a few tweaks to naming as I went.

A few cases use keyed unions when they should be kinded; this is a
significant todo.

A few cases use keyed unions where the schema-schema declaration says
they should use inline representations!  In these, I've come to believe
the schema-schema made a mistake; we probably will update it.

The overall structure, however, is not significantly diverged.

The whole specification is still written in code: the 'SpawnFoo'
placeholder methods are in heavy use.  (This might herald the beginning
of the end, for them, though!)  (We're also still making little
hacks to dodge the current placeholder typeinfo's lack of support
for inline defns; but this is purely a problem of the placeholder
typeinfo structures, and can disappear the instant we replace them.)

If you run this generation, the emitted code is (aside from those
caveats listed above) suitable for parsing schema declarations.

...!

Which means... we can soon turn around and start using this to build
up tooling which actually uses schema JSON as a config mechanism.
Which will then bring us quite a bit closer to being able to make
free-standing usable CLI tools for working with further codegen.

There's a few other bits to go.  For starters, right now, this is
just generating output into a demo output dir.  I've made no attempt
in this commit to rig it up as a proper snake-eating-its-tail by
replacing the 'SpawnFoo' methods and placeholder type info; that'll
come in due time.  (And I think we may still have fun choices coming
up with that, incidentally; the distinction between string type names
and reified pointers is still looming, and we need to figure out what
the story is for gen outputs containing their own type descriptions
(which may touch on the same interface design choices); etc.)  I'll
probably move somewhat cautiously with this, and only cut over after
polishing the gen outputs some more... but it's now near in reach.

The size of the generated output is also very likely to need work.
We're looking something on the order of 1.6MB of generated output.
(It's *highly* redundant: if you gzip it, it's 95kb.)  Mind: I've made
*no* effort whatsoever to bring this down.  So, it's probably safe to
assume we'll find some low-hanging fruit when we actually look into it.
(I'm not yet sure what the bar will be for satisfaction with this:
I regard the current number as vaguely "seems rather high", but it's
also for a fairly sizable schema and for a lot of features provided,
so maybe some size trades are just what we're going to face in golang.)

That's it.  There will probably be some PRs to the schema-schema
documents in the specs repo shortly.  Other than those, this should
also be about ready to line up with and parse JSON output created
by the other IPLD Schema DSL->JSON parsers we already have, which
could start unlocking some really neat stuff.  🎉
parent 8eda117b
package schemaschema
import (
"fmt"
"os"
"github.com/ipld/go-ipld-prime/schema"
gengo "github.com/ipld/go-ipld-prime/schema/gen/go"
)
func init() {
ts := schema.TypeSystem{}
ts.Init()
adjCfg := &gengo.AdjunctCfg{
FieldSymbolLowerOverrides: map[gengo.FieldTuple]string{
{"StructField", "type"}: "typ",
{"TypeEnum", "type"}: "typ",
},
CfgUnionMemlayout: map[schema.TypeName]string{
"TypeDefnInline": "interface", // breaks cycles in embeddery that would otherwise be problematic.
},
}
// I've elided all references to Advancedlayouts stuff for the moment.
// (Not because it's particularly hard or problematic; I just want to draw a slightly smaller circle first.)
// Prelude
ts.Accumulate(schema.SpawnString("String"))
ts.Accumulate(schema.SpawnBool("Bool"))
ts.Accumulate(schema.SpawnInt("Int"))
ts.Accumulate(schema.SpawnFloat("Float"))
ts.Accumulate(schema.SpawnBytes("Bytes"))
// Schema-schema!
ts.Accumulate(schema.SpawnString("TypeName"))
ts.Accumulate(schema.SpawnMap("SchemaMap",
"TypeName", "TypeDefn", false,
))
ts.Accumulate(schema.SpawnUnion("TypeDefn",
[]schema.TypeName{
"TypeBool",
"TypeString",
"TypeBytes",
"TypeInt",
"TypeFloat",
"TypeMap",
"TypeList",
"TypeLink",
"TypeUnion",
"TypeStruct",
"TypeEnum",
"TypeCopy",
},
schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{
"bool": "TypeBool",
"string": "TypeString",
"bytes": "TypeBytes",
"int": "TypeInt",
"float": "TypeFloat",
"map": "TypeMap",
"list": "TypeList",
"link": "TypeLink",
"union": "TypeUnion",
"struct": "TypeStruct",
"enum": "TypeEnum",
"copy": "TypeCopy",
}),
))
ts.Accumulate(schema.SpawnUnion("TypeNameOrInlineDefn",
[]schema.TypeName{
"TypeName",
"TypeDefnInline",
},
schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{ // FIXME: this should actually be kinded.
"string": "TypeName",
"map": "TypeDefnInline",
}),
))
ts.Accumulate(schema.SpawnUnion("TypeDefnInline", // n.b. previously called "TypeTerm".
[]schema.TypeName{
"TypeMap",
"TypeList",
},
schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{
"map": "TypeMap",
"list": "TypeList",
}),
))
ts.Accumulate(schema.SpawnStruct("TypeBool",
[]schema.StructField{},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnStruct("TypeString",
[]schema.StructField{},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnStruct("TypeBytes",
[]schema.StructField{},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnStruct("TypeInt",
[]schema.StructField{},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnStruct("TypeFloat",
[]schema.StructField{},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnStruct("TypeLink",
[]schema.StructField{
schema.SpawnStructField("expectedType", "TypeName", true, false), // todo: this uses an implicit with a value of 'any' in the schema-schema, but that's been questioned before. maybe it should simply be an optional.
},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnStruct("TypeMap",
[]schema.StructField{
schema.SpawnStructField("keyType", "TypeName", false, false),
schema.SpawnStructField("valueType", "TypeNameOrInlineDefn", false, false),
schema.SpawnStructField("valueNullable", "Bool", false, false), // todo: wants to use the "implicit" feature, but not supported yet
schema.SpawnStructField("representation", "MapRepresentation", false, false),
},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnUnion("MapRepresentation",
[]schema.TypeName{
"MapRepresentation_Map",
"MapRepresentation_StringPairs",
"MapRepresentation_ListPairs",
},
schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{
"map": "MapRepresentation_Map",
"stringpairs": "MapRepresentation_StringPairs",
"listpairs": "MapRepresentation_ListPairs",
}),
))
ts.Accumulate(schema.SpawnStruct("MapRepresentation_Map",
[]schema.StructField{},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnStruct("MapRepresentation_StringPairs",
[]schema.StructField{
schema.SpawnStructField("innerDelim", "String", false, false),
schema.SpawnStructField("entryDelim", "String", false, false),
},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnStruct("MapRepresentation_ListPairs",
[]schema.StructField{},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnStruct("TypeList",
[]schema.StructField{
schema.SpawnStructField("valueType", "TypeNameOrInlineDefn", false, false),
schema.SpawnStructField("valueNullable", "Bool", false, false), // todo: wants to use the "implicit" feature, but not supported yet
schema.SpawnStructField("representation", "ListRepresentation", false, false),
},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnUnion("ListRepresentation",
[]schema.TypeName{
"ListRepresentation_List",
},
schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{
"list": "ListRepresentation_List",
}),
))
ts.Accumulate(schema.SpawnStruct("ListRepresentation_List",
[]schema.StructField{},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnStruct("TypeUnion",
[]schema.StructField{
schema.SpawnStructField("members", "List__TypeName", false, false), // todo: this is a slight hack: should be using an inline defn, but we banged it with name munge coincidents to simplify bootstrap.
schema.SpawnStructField("representation", "UnionRepresentation", false, false),
},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnList("List__TypeName", // todo: this is a slight hack: should be an anon inside TypeUnion.members.
"TypeName", false,
))
ts.Accumulate(schema.SpawnUnion("UnionRepresentation",
[]schema.TypeName{
"UnionRepresentation_Kinded",
"UnionRepresentation_Keyed",
"UnionRepresentation_Envelope",
"UnionRepresentation_Inline",
"UnionRepresentation_BytePrefix",
},
schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{
"kinded": "UnionRepresentation_Kinded",
"keyed": "UnionRepresentation_Keyed",
"envelope": "UnionRepresentation_Envelope",
"inline": "UnionRepresentation_Inline",
"byteprefix": "UnionRepresentation_BytePrefix",
}),
))
ts.Accumulate(schema.SpawnMap("UnionRepresentation_Kinded",
"RepresentationKind", "TypeName", false,
))
ts.Accumulate(schema.SpawnMap("UnionRepresentation_Keyed",
"String", "TypeName", false,
))
ts.Accumulate(schema.SpawnStruct("UnionRepresentation_Envelope",
[]schema.StructField{
schema.SpawnStructField("discriminantKey", "String", false, false),
schema.SpawnStructField("contentKey", "String", false, false),
schema.SpawnStructField("discriminantTable", "Map__String__TypeName", false, false), // todo: dodging inline defn's again.
},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnStruct("UnionRepresentation_Inline",
[]schema.StructField{
schema.SpawnStructField("discriminantKey", "String", false, false),
schema.SpawnStructField("discriminantTable", "Map__String__TypeName", false, false), // todo: dodging inline defn's again.
},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnStruct("UnionRepresentation_BytePrefix",
[]schema.StructField{
schema.SpawnStructField("discriminantTable", "Map__TypeName__Int", false, false), // todo: dodging inline defn's again.
},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnMap("Map__String__TypeName",
"String", "TypeName", false,
))
ts.Accumulate(schema.SpawnMap("Map__TypeName__Int",
"String", "Int", false,
))
ts.Accumulate(schema.SpawnString("RepresentationKind")) // todo: RepresentationKind is supposed to be an enum, but we're puting it to a string atm.
ts.Accumulate(schema.SpawnStruct("TypeStruct",
[]schema.StructField{
schema.SpawnStructField("fields", "Map__FieldName__StructField", false, false), // todo: dodging inline defn's again.
schema.SpawnStructField("representation", "StructRepresentation", false, false),
},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnMap("Map__FieldName__StructField",
"FieldName", "StructField", false,
))
ts.Accumulate(schema.SpawnString("FieldName"))
ts.Accumulate(schema.SpawnStruct("StructField",
[]schema.StructField{
schema.SpawnStructField("type", "TypeDefnInline", false, false),
schema.SpawnStructField("optional", "Bool", false, false), // todo: wants to use the "implicit" feature, but not supported yet
schema.SpawnStructField("nullable", "Bool", false, false), // todo: wants to use the "implicit" feature, but not supported yet
},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnUnion("StructRepresentation",
[]schema.TypeName{
"StructRepresentation_Map",
"StructRepresentation_Tuple",
"StructRepresentation_StringPairs",
"StructRepresentation_StringJoin",
"StructRepresentation_ListPairs",
},
schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{
"map": "StructRepresentation_Map",
"tuple": "StructRepresentation_Tuple",
"stringpairs": "StructRepresentation_StringPairs",
"stringjoin": "StructRepresentation_StringJoin",
"listpairs": "StructRepresentation_ListPairs",
}),
))
ts.Accumulate(schema.SpawnStruct("StructRepresentation_Map",
[]schema.StructField{
schema.SpawnStructField("fields", "Map__FieldName__StructRepresentation_Map_FieldDetails", true, false), // todo: dodging inline defn's again.
},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnMap("Map__FieldName__StructRepresentation_Map_FieldDetails",
"FieldName", "StructRepresentation_Map_FieldDetails", false,
))
ts.Accumulate(schema.SpawnStruct("StructRepresentation_Map_FieldDetails",
[]schema.StructField{
schema.SpawnStructField("rename", "String", true, false),
schema.SpawnStructField("implicit", "AnyScalar", true, false),
},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnStruct("StructRepresentation_Tuple",
[]schema.StructField{
schema.SpawnStructField("fieldOrder", "List__FieldName", true, false), // todo: dodging inline defn's again.
},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnList("List__FieldName",
"FieldName", false,
))
ts.Accumulate(schema.SpawnStruct("StructRepresentation_StringPairs",
[]schema.StructField{
schema.SpawnStructField("innerDelim", "String", false, false),
schema.SpawnStructField("entryDelim", "String", false, false),
},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnStruct("StructRepresentation_StringJoin",
[]schema.StructField{
schema.SpawnStructField("join", "String", false, false), // review: "delim" would seem more consistent with others -- but this is currently what the schema-schema says.
schema.SpawnStructField("fieldOrder", "List__FieldName", true, false), // todo: dodging inline defn's again.
},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnStruct("StructRepresentation_ListPairs",
[]schema.StructField{},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnStruct("TypeEnum",
[]schema.StructField{
schema.SpawnStructField("type", "Map__EnumValue__Unit", false, false), // todo: dodging inline defn's again. also: this says unit; schema-schema does not. schema-schema needs revisiting on this subject.
schema.SpawnStructField("representation", "EnumRepresentation", false, false),
},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnMap("Map__EnumValue__Unit",
"EnumValue", "Unit", false,
))
ts.Accumulate(schema.SpawnStruct("Unit", // todo: we should formalize the introdution of unit as first class type kind.
[]schema.StructField{},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnUnion("EnumRepresentation",
[]schema.TypeName{
"EnumRepresentation_String",
"EnumRepresentation_Int",
},
schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{
"string": "EnumRepresentation_String",
"int": "EnumRepresentation_Int",
}),
))
ts.Accumulate(schema.SpawnString("EnumValue"))
ts.Accumulate(schema.SpawnMap("EnumRepresentation_String",
"EnumValue", "String", false,
))
ts.Accumulate(schema.SpawnMap("EnumRepresentation_Int",
"EnumValue", "Int", false,
))
ts.Accumulate(schema.SpawnStruct("TypeCopy",
[]schema.StructField{
schema.SpawnStructField("fromType", "TypeName", false, false),
},
schema.StructRepresentation_Map{},
))
ts.Accumulate(schema.SpawnUnion("AnyScalar",
[]schema.TypeName{
"Bool",
"String",
"Bytes",
"Int",
"Float",
},
schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{ // FIXME: this should actually be kinded.
"bool": "Bool",
"string": "String",
"bytes": "Bytes",
"int": "Int",
"float": "Float",
}),
))
if errs := ts.ValidateGraph(); errs != nil {
for _, err := range errs {
fmt.Printf("- %s\n", err)
}
panic("not happening")
}
os.Mkdir("./schema", 0755)
gengo.Generate("./schema", "schema", ts, adjCfg)
}
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