From a6ca7b407566bbef6b8432db7c9a7e2fea9247d7 Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Wed, 27 Apr 2022 09:51:19 +1000 Subject: [PATCH] schema: enable inline types through dsl parser & compiler (#404) --- .ipld | 2 +- schema/dmt/compile.go | 74 ++++++++++++++++++++++++++++++++------- schema/dsl/parse.go | 22 ++++++++---- schema/gen/go/generate.go | 2 +- 4 files changed, 79 insertions(+), 21 deletions(-) diff --git a/.ipld b/.ipld index 1cff3629..caedc8d7 160000 --- a/.ipld +++ b/.ipld @@ -1 +1 @@ -Subproject commit 1cff36290ba399dddc2de06ef044f83597145ce8 +Subproject commit caedc8d768e027f4722c3ac3d4f743d5ec43b5d7 diff --git a/schema/dmt/compile.go b/schema/dmt/compile.go index 5487216c..f512ccca 100644 --- a/schema/dmt/compile.go +++ b/schema/dmt/compile.go @@ -66,7 +66,7 @@ func todoFromImplicitlyFalseBool(b *bool) bool { return *b } -func todoAnonTypeName(nameOrDefn TypeNameOrInlineDefn) string { +func anonTypeName(nameOrDefn TypeNameOrInlineDefn) string { if nameOrDefn.TypeName != nil { return *nameOrDefn.TypeName } @@ -74,15 +74,24 @@ func todoAnonTypeName(nameOrDefn TypeNameOrInlineDefn) string { switch { case defn.TypeDefnMap != nil: defn := defn.TypeDefnMap - return fmt.Sprintf("Map__%s__%s", defn.KeyType, todoAnonTypeName(defn.ValueType)) + return fmt.Sprintf("Map__%s__%s", defn.KeyType, anonTypeName(defn.ValueType)) case defn.TypeDefnList != nil: defn := defn.TypeDefnList - return fmt.Sprintf("List__%s", todoAnonTypeName(defn.ValueType)) + return fmt.Sprintf("List__%s", anonTypeName(defn.ValueType)) + case defn.TypeDefnLink != nil: + return anonLinkName(*defn.TypeDefnLink) default: panic(fmt.Errorf("%#v", defn)) } } +func anonLinkName(defn TypeDefnLink) string { + if defn.ExpectedType != nil { + return fmt.Sprintf("Link__%s", *defn.ExpectedType) + } + return "Link__Link" +} + func parseKind(s string) datamodel.Kind { switch s { case "map": @@ -124,8 +133,20 @@ func spawnType(ts *schema.TypeSystem, name schema.TypeName, defn TypeDefn) (sche case defn.TypeDefnList != nil: typ := defn.TypeDefnList - if typ.ValueType.InlineDefn != nil { - return nil, fmt.Errorf("TODO: support anonymous types in schema package") + tname := "" + if typ.ValueType.TypeName != nil { + tname = *typ.ValueType.TypeName + } else if tname = anonTypeName(typ.ValueType); ts.TypeByName(tname) == nil { + anonDefn := TypeDefn{ + TypeDefnMap: typ.ValueType.InlineDefn.TypeDefnMap, + TypeDefnList: typ.ValueType.InlineDefn.TypeDefnList, + TypeDefnLink: typ.ValueType.InlineDefn.TypeDefnLink, + } + anonType, err := spawnType(ts, tname, anonDefn) + if err != nil { + return nil, err + } + ts.Accumulate(anonType) } switch { case typ.Representation == nil || @@ -135,13 +156,25 @@ func spawnType(ts *schema.TypeSystem, name schema.TypeName, defn TypeDefn) (sche return nil, fmt.Errorf("TODO: support other list repr in schema package") } return schema.SpawnList(name, - *typ.ValueType.TypeName, + tname, todoFromImplicitlyFalseBool(typ.ValueNullable), ), nil case defn.TypeDefnMap != nil: typ := defn.TypeDefnMap - if typ.ValueType.InlineDefn != nil { - return nil, fmt.Errorf("TODO: support anonymous types in schema package") + tname := "" + if typ.ValueType.TypeName != nil { + tname = *typ.ValueType.TypeName + } else if tname = anonTypeName(typ.ValueType); ts.TypeByName(tname) == nil { + anonDefn := TypeDefn{ + TypeDefnMap: typ.ValueType.InlineDefn.TypeDefnMap, + TypeDefnList: typ.ValueType.InlineDefn.TypeDefnList, + TypeDefnLink: typ.ValueType.InlineDefn.TypeDefnLink, + } + anonType, err := spawnType(ts, tname, anonDefn) + if err != nil { + return nil, err + } + ts.Accumulate(anonType) } switch { case typ.Representation == nil || @@ -154,7 +187,7 @@ func spawnType(ts *schema.TypeSystem, name schema.TypeName, defn TypeDefn) (sche } return schema.SpawnMap(name, typ.KeyType, - *typ.ValueType.TypeName, + tname, todoFromImplicitlyFalseBool(typ.ValueNullable), ), nil case defn.TypeDefnStruct != nil: @@ -165,7 +198,7 @@ func spawnType(ts *schema.TypeSystem, name schema.TypeName, defn TypeDefn) (sche tname := "" if field.Type.TypeName != nil { tname = *field.Type.TypeName - } else if tname = todoAnonTypeName(field.Type); ts.TypeByName(tname) == nil { + } else if tname = anonTypeName(field.Type); ts.TypeByName(tname) == nil { // Note that TypeDefn and InlineDefn aren't the same enum. anonDefn := TypeDefn{ TypeDefnMap: field.Type.InlineDefn.TypeDefnMap, @@ -243,7 +276,18 @@ func spawnType(ts *schema.TypeSystem, name schema.TypeName, defn TypeDefn) (sche if member.TypeName != nil { members = append(members, *member.TypeName) } else { - panic("TODO: inline union members") + tname := anonLinkName(*member.UnionMemberInlineDefn.TypeDefnLink) + members = append(members, tname) + if ts.TypeByName(tname) == nil { + anonDefn := TypeDefn{ + TypeDefnLink: member.UnionMemberInlineDefn.TypeDefnLink, + } + anonType, err := spawnType(ts, tname, anonDefn) + if err != nil { + return nil, err + } + ts.Accumulate(anonType) + } } } remainingMembers := make(map[string]bool) @@ -276,7 +320,9 @@ func spawnType(ts *schema.TypeSystem, name schema.TypeName, defn TypeDefn) (sche validMember(memberName) table[kind] = memberName case member.UnionMemberInlineDefn != nil: - panic("TODO: inline defn support") + tname := anonLinkName(*member.UnionMemberInlineDefn.TypeDefnLink) + validMember(tname) + table[kind] = tname } } repr = schema.SpawnUnionRepresentationKinded(table) @@ -291,7 +337,9 @@ func spawnType(ts *schema.TypeSystem, name schema.TypeName, defn TypeDefn) (sche validMember(memberName) table[key] = memberName case member.UnionMemberInlineDefn != nil: - panic("TODO: inline defn support") + tname := anonLinkName(*member.UnionMemberInlineDefn.TypeDefnLink) + validMember(tname) + table[key] = tname } } repr = schema.SpawnUnionRepresentationKeyed(table) diff --git a/schema/dsl/parse.go b/schema/dsl/parse.go index b08a4a5b..b1cf2e0b 100644 --- a/schema/dsl/parse.go +++ b/schema/dsl/parse.go @@ -478,11 +478,14 @@ func (p *parser) typeNameOrInlineDefn() (dmt.TypeNameOrInlineDefn, error) { if err != nil { return typ, err } - if tok == "&" { - return typ, p.errf("TODO: links") - } switch tok { + case "&": + expectedName, err := p.consumeName() + if err != nil { + return typ, err + } + typ.InlineDefn = &dmt.InlineDefn{TypeDefnLink: &dmt.TypeDefnLink{ExpectedType: &expectedName}} case "[": tlist, err := p.typeList() if err != nil { @@ -574,13 +577,20 @@ func (p *parser) typeUnion() (*dmt.TypeDefnUnion, error) { return nil, p.errf("expected %q or %q, got %q", "}", "|", tok) } var member dmt.UnionMember - name, err := p.consumeName() + nameOrInline, err := p.typeNameOrInlineDefn() if err != nil { return nil, err } - // TODO: inline defn - member.TypeName = &name + if nameOrInline.TypeName != nil { + member.TypeName = nameOrInline.TypeName + } else { + if nameOrInline.InlineDefn.TypeDefnLink != nil { + member.UnionMemberInlineDefn = &dmt.UnionMemberInlineDefn{TypeDefnLink: nameOrInline.InlineDefn.TypeDefnLink} + } else { + return nil, p.errf("expected a name or inline link, got neither") + } + } defn.Members = append(defn.Members, member) key, err := p.consumeToken() diff --git a/schema/gen/go/generate.go b/schema/gen/go/generate.go index e57be15f..5d4367e7 100644 --- a/schema/gen/go/generate.go +++ b/schema/gen/go/generate.go @@ -82,7 +82,7 @@ func Generate(pth string, pkgName string, ts schema.TypeSystem, adjCfg *AdjunctC panic("unrecognized union representation strategy") } default: - panic("add more type switches here :)") + panic(fmt.Sprintf("add more type switches here :), failed at type %s", tn)) } } }