Prepare TypeGenerator being a Kind for Properties.
Right now the two-pass tooling system has issues with establishing doubly-linked data between Functiona/NonFunctional Properties (which have Kinds abstractions) and Types (which have Property abstraction). While the experimental tool compiles, it panics at runtime currently because the TypeGenerator needs to look at properties with Range of itself, but it is applying itself to properties with Domain of its type. Which is wrong. Will need to stew on this and think of how to avoid making even more shortcuts and hacky solutions in the name of progress.
このコミットが含まれているのは:
コミット
a3c3a7b5fc
|
@ -4,7 +4,6 @@ import (
|
|||
"fmt"
|
||||
"github.com/cjslep/activity/tools/exp/props"
|
||||
"github.com/cjslep/activity/tools/exp/rdf"
|
||||
"github.com/cjslep/activity/tools/exp/types"
|
||||
"github.com/dave/jennifer/jen"
|
||||
"strings"
|
||||
)
|
||||
|
@ -19,7 +18,7 @@ type vocabulary struct {
|
|||
Kinds map[string]*props.Kind
|
||||
FProps map[string]*props.FunctionalPropertyGenerator
|
||||
NFProps map[string]*props.NonFunctionalPropertyGenerator
|
||||
Types map[string]*types.TypeGenerator
|
||||
Types map[string]*props.TypeGenerator
|
||||
}
|
||||
|
||||
func newVocabulary() vocabulary {
|
||||
|
@ -27,7 +26,7 @@ func newVocabulary() vocabulary {
|
|||
Kinds: make(map[string]*props.Kind, 0),
|
||||
FProps: make(map[string]*props.FunctionalPropertyGenerator, 0),
|
||||
NFProps: make(map[string]*props.NonFunctionalPropertyGenerator, 0),
|
||||
Types: make(map[string]*types.TypeGenerator, 0),
|
||||
Types: make(map[string]*props.TypeGenerator, 0),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,7 +67,7 @@ func (c Converter) Convert(p *rdf.ParsedVocabulary) (f []*File, e error) {
|
|||
|
||||
func (c Converter) convertToFiles(v vocabulary) (f []*File, e error) {
|
||||
for _, _ = range v.Kinds {
|
||||
// TODO
|
||||
// TODO: Implement
|
||||
}
|
||||
for _, i := range v.FProps {
|
||||
var pkg string
|
||||
|
@ -131,6 +130,16 @@ func (c Converter) convertToFiles(v vocabulary) (f []*File, e error) {
|
|||
return
|
||||
}
|
||||
|
||||
// convertVocabulary works in a two-pass system: first converting all known
|
||||
// properties, and then the types.
|
||||
//
|
||||
// Due to the fact that properties rely on the Kind abstraction, and both
|
||||
// properties and types can be Kinds, this introduces tight coupling between
|
||||
// the two so that callbacks can fill in missing links in data that isn't known
|
||||
// beforehand (ex: how to serialize, deserialize, and compare types).
|
||||
//
|
||||
// This feels very hacky and could be decoupled using standard design patterns,
|
||||
// but since there is no need, it isn't addressed now.
|
||||
func (c Converter) convertVocabulary(p *rdf.ParsedVocabulary) (v vocabulary, e error) {
|
||||
v = newVocabulary()
|
||||
for k, val := range p.Vocab.Values {
|
||||
|
@ -159,7 +168,7 @@ func (c Converter) convertVocabulary(p *rdf.ParsedVocabulary) (v vocabulary, e e
|
|||
stuck := true
|
||||
for i, t := range allTypes {
|
||||
if allExtendsAreIn(t, v.Types) {
|
||||
var tg *types.TypeGenerator
|
||||
var tg *props.TypeGenerator
|
||||
tg, e = c.convertType(t, p.Vocab, v.FProps, v.NFProps, v.Types)
|
||||
if e != nil {
|
||||
return
|
||||
|
@ -173,7 +182,7 @@ func (c Converter) convertVocabulary(p *rdf.ParsedVocabulary) (v vocabulary, e e
|
|||
}
|
||||
}
|
||||
if stuck {
|
||||
e = fmt.Errorf("converting types got stuck in dependency cycle")
|
||||
e = fmt.Errorf("converting props got stuck in dependency cycle")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -184,46 +193,70 @@ func (c Converter) convertType(t rdf.VocabularyType,
|
|||
v rdf.Vocabulary,
|
||||
existingFProps map[string]*props.FunctionalPropertyGenerator,
|
||||
existingNFProps map[string]*props.NonFunctionalPropertyGenerator,
|
||||
existingTypes map[string]*types.TypeGenerator) (tg *types.TypeGenerator, e error) {
|
||||
// Determine the types package name
|
||||
existingTypes map[string]*props.TypeGenerator) (tg *props.TypeGenerator, e error) {
|
||||
// Determine the props package name
|
||||
var pkg string
|
||||
pkg, e = c.typePackageName(t)
|
||||
if e != nil {
|
||||
return
|
||||
}
|
||||
// Determine the properties for this type
|
||||
var p []types.Property
|
||||
for _, prop := range v.Properties {
|
||||
for _, ref := range prop.Domain {
|
||||
if len(ref.Vocab) != 0 {
|
||||
e = fmt.Errorf("unhandled use case: property domain outside its vocabulary")
|
||||
return
|
||||
} else if ref.Name == t.Name {
|
||||
if prop.Functional {
|
||||
p = append(p, existingFProps[prop.Name])
|
||||
} else {
|
||||
p = append(p, existingNFProps[prop.Name])
|
||||
var p []props.Property
|
||||
for _, prop := range t.Properties {
|
||||
if len(prop.Vocab) != 0 {
|
||||
e = fmt.Errorf("unhandled use case: property domain outside its vocabulary")
|
||||
return
|
||||
} else {
|
||||
var property props.Property
|
||||
var ok bool
|
||||
property, ok = existingFProps[prop.Name]
|
||||
if !ok {
|
||||
property, ok = existingNFProps[prop.Name]
|
||||
if !ok {
|
||||
e = fmt.Errorf("cannot find property with name: %s", prop.Name)
|
||||
return
|
||||
}
|
||||
break
|
||||
}
|
||||
p = append(p, property)
|
||||
}
|
||||
}
|
||||
// Determine WithoutProperties for this type
|
||||
var wop []props.Property
|
||||
for _, prop := range t.WithoutProperties {
|
||||
if len(prop.Vocab) != 0 {
|
||||
e = fmt.Errorf("unhandled use case: withoutproperty domain outside its vocabulary")
|
||||
return
|
||||
} else {
|
||||
var property props.Property
|
||||
var ok bool
|
||||
property, ok = existingFProps[prop.Name]
|
||||
if !ok {
|
||||
property, ok = existingNFProps[prop.Name]
|
||||
if !ok {
|
||||
e = fmt.Errorf("cannot find property with name: %s", prop.Name)
|
||||
return
|
||||
}
|
||||
}
|
||||
wop = append(wop, property)
|
||||
}
|
||||
}
|
||||
// Determine what this type extends
|
||||
var ext []*types.TypeGenerator
|
||||
var ext []*props.TypeGenerator
|
||||
for _, ex := range t.Extends {
|
||||
if len(ex.Vocab) != 0 {
|
||||
// TODO: This should be fixed
|
||||
// TODO: This should be fixed to handle references
|
||||
e = fmt.Errorf("unhandled use case: type extends another type outside its vocabulary")
|
||||
return
|
||||
} else {
|
||||
ext = append(ext, existingTypes[ex.Name])
|
||||
}
|
||||
}
|
||||
tg, e = types.NewTypeGenerator(
|
||||
tg, e = props.NewTypeGenerator(
|
||||
pkg,
|
||||
c.convertTypeToName(t),
|
||||
t.Notes,
|
||||
p,
|
||||
wop,
|
||||
ext,
|
||||
nil)
|
||||
if e != nil {
|
||||
|
@ -232,7 +265,7 @@ func (c Converter) convertType(t rdf.VocabularyType,
|
|||
// Apply disjoint if both sides are available.
|
||||
for _, disj := range t.DisjointWith {
|
||||
if len(disj.Vocab) != 0 {
|
||||
// TODO: This should be fixed
|
||||
// TODO: This should be fixed to handle references
|
||||
e = fmt.Errorf("unhandled use case: type is disjoint with another type outside its vocabulary")
|
||||
return
|
||||
} else if disjointType, ok := existingTypes[disj.Name]; ok {
|
||||
|
@ -300,19 +333,18 @@ func (c Converter) convertValue(v rdf.VocabularyValue) (k *props.Kind) {
|
|||
}
|
||||
|
||||
func (c Converter) convertTypeToKind(v rdf.VocabularyType) (k *props.Kind, e error) {
|
||||
var pkg string
|
||||
pkg, e = c.typePackageName(v)
|
||||
if e != nil {
|
||||
return
|
||||
}
|
||||
s, d, l := types.KindSerializationFuncs(pkg, c.convertTypeToName(v))
|
||||
k = &props.Kind{
|
||||
Name: c.toIdentifier(v),
|
||||
ConcreteKind: c.convertTypeToConcreteKind(v),
|
||||
Nilable: true,
|
||||
SerializeFn: s,
|
||||
DeserializeFn: d,
|
||||
LessFn: l,
|
||||
Name: c.toIdentifier(v),
|
||||
ConcreteKind: c.convertTypeToConcreteKind(v),
|
||||
Nilable: true,
|
||||
// Instead of populating:
|
||||
// - SerializeFn
|
||||
// - DeserializeFn
|
||||
// - LessFn
|
||||
//
|
||||
// The TypeGenerator is responsible for calling setKindFns on
|
||||
// the properties, to property wire a Property's Kind back to
|
||||
// the Type's implementation.
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -409,7 +441,7 @@ func (c Converter) propertyPackageName(v rdf.VocabularyProperty) (pkg string, e
|
|||
return
|
||||
}
|
||||
|
||||
func (c Converter) typePackageDirectory(v *types.TypeGenerator) (dir string, e error) {
|
||||
func (c Converter) typePackageDirectory(v *props.TypeGenerator) (dir string, e error) {
|
||||
switch c.TypePackagePolicy {
|
||||
case TypeFlatUnderRoot:
|
||||
dir = fmt.Sprintf("%s/%s/", c.VocabularyRoot, c.TypePackageRoot)
|
||||
|
@ -423,7 +455,7 @@ func (c Converter) typePackageDirectory(v *types.TypeGenerator) (dir string, e e
|
|||
return
|
||||
}
|
||||
|
||||
func (c Converter) typePackageFile(v *types.TypeGenerator) (pkg string, e error) {
|
||||
func (c Converter) typePackageFile(v *props.TypeGenerator) (pkg string, e error) {
|
||||
switch c.TypePackagePolicy {
|
||||
case TypeFlatUnderRoot:
|
||||
pkg = fmt.Sprintf("%s/%s", c.VocabularyRoot, c.TypePackageRoot)
|
||||
|
@ -485,10 +517,10 @@ func (c Converter) isNilable(goType string) bool {
|
|||
return goType[0] == '*'
|
||||
}
|
||||
|
||||
func allExtendsAreIn(t rdf.VocabularyType, v map[string]*types.TypeGenerator) bool {
|
||||
func allExtendsAreIn(t rdf.VocabularyType, v map[string]*props.TypeGenerator) bool {
|
||||
for _, e := range t.Extends {
|
||||
if len(e.Vocab) != 0 {
|
||||
// TODO: Handle references
|
||||
// TODO: This should be fixed to handle references
|
||||
return false
|
||||
} else if _, ok := v[e.Name]; !ok {
|
||||
return false
|
||||
|
|
|
@ -320,7 +320,7 @@ func (p *FunctionalPropertyGenerator) serializationFuncs() ([]*codegen.Method, [
|
|||
deserialize = append(deserialize,
|
||||
codegen.NewCommentedFunction(
|
||||
p.packageName(),
|
||||
p.deserializeFnName(),
|
||||
p.DeserializeFnName(),
|
||||
[]jen.Code{jen.Id("i").Interface()},
|
||||
[]jen.Code{jen.Op("*").Id(p.StructName()), jen.Error()},
|
||||
[]jen.Code{
|
||||
|
@ -330,13 +330,13 @@ func (p *FunctionalPropertyGenerator) serializationFuncs() ([]*codegen.Method, [
|
|||
jen.Nil(),
|
||||
),
|
||||
},
|
||||
jen.Commentf("%s creates an iterator from an element that has been unmarshalled from a text or binary format.", p.deserializeFnName()),
|
||||
jen.Commentf("%s creates an iterator from an element that has been unmarshalled from a text or binary format.", p.DeserializeFnName()),
|
||||
))
|
||||
} else {
|
||||
deserialize = append(deserialize,
|
||||
codegen.NewCommentedFunction(
|
||||
p.packageName(),
|
||||
p.deserializeFnName(),
|
||||
p.DeserializeFnName(),
|
||||
[]jen.Code{jen.Id("m").Map(jen.String()).Interface()},
|
||||
[]jen.Code{jen.Op("*").Id(p.StructName()), jen.Error()},
|
||||
[]jen.Code{
|
||||
|
@ -356,7 +356,7 @@ func (p *FunctionalPropertyGenerator) serializationFuncs() ([]*codegen.Method, [
|
|||
jen.Nil(),
|
||||
),
|
||||
},
|
||||
jen.Commentf("%s creates a %q property from an interface representation that has been unmarshalled from a text or binary format.", p.deserializeFnName(), p.PropertyName()),
|
||||
jen.Commentf("%s creates a %q property from an interface representation that has been unmarshalled from a text or binary format.", p.DeserializeFnName(), p.PropertyName()),
|
||||
))
|
||||
}
|
||||
return serialize, deserialize
|
||||
|
|
|
@ -303,7 +303,7 @@ func (p *NonFunctionalPropertyGenerator) serializationFuncs() ([]*codegen.Method
|
|||
jen.List(
|
||||
jen.Id("p"),
|
||||
jen.Err(),
|
||||
).Op(":=").Id(p.elementTypeGenerator().deserializeFnName()).Call(
|
||||
).Op(":=").Id(p.elementTypeGenerator().DeserializeFnName()).Call(
|
||||
jen.Id(variable),
|
||||
),
|
||||
jen.Err().Op("!=").Nil(),
|
||||
|
@ -324,7 +324,7 @@ func (p *NonFunctionalPropertyGenerator) serializationFuncs() ([]*codegen.Method
|
|||
deserialize := []*codegen.Function{
|
||||
codegen.NewCommentedFunction(
|
||||
p.packageName(),
|
||||
p.deserializeFnName(),
|
||||
p.DeserializeFnName(),
|
||||
[]jen.Code{jen.Id("m").Map(jen.String()).Interface()},
|
||||
[]jen.Code{jen.Id(p.StructName()), jen.Error()},
|
||||
[]jen.Code{
|
||||
|
@ -364,7 +364,7 @@ func (p *NonFunctionalPropertyGenerator) serializationFuncs() ([]*codegen.Method
|
|||
jen.Nil(),
|
||||
),
|
||||
},
|
||||
jen.Commentf("%s creates a %q property from an interface representation that has been unmarshalled from a text or binary format.", p.deserializeFnName(), p.PropertyName()),
|
||||
jen.Commentf("%s creates a %q property from an interface representation that has been unmarshalled from a text or binary format.", p.DeserializeFnName(), p.PropertyName()),
|
||||
),
|
||||
}
|
||||
return serialize, deserialize
|
||||
|
|
|
@ -89,6 +89,27 @@ func (p *PropertyGenerator) packageName() string {
|
|||
return p.Package
|
||||
}
|
||||
|
||||
// SetKindFns allows TypeGenerators to later notify this Property what functions
|
||||
// to use when generating the serialization code.
|
||||
//
|
||||
// The name parameter must match the LowerName of an Identifier.
|
||||
//
|
||||
// This feels very hacky.
|
||||
func (p *PropertyGenerator) SetKindFns(name string, ser, deser, less *codegen.Function) error {
|
||||
for _, kind := range p.Kinds {
|
||||
if kind.Name.LowerName == name {
|
||||
if kind.SerializeFn != nil || kind.DeserializeFn != nil || kind.LessFn != nil {
|
||||
return fmt.Errorf("property kind already has serialization functions set for %q", name)
|
||||
}
|
||||
kind.SerializeFn = ser
|
||||
kind.DeserializeFn = deser
|
||||
kind.LessFn = less
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("cannot find property kind %q", name)
|
||||
}
|
||||
|
||||
// StructName returns the name of the type, which may or may not be a struct,
|
||||
// to generate.
|
||||
func (p *PropertyGenerator) StructName() string {
|
||||
|
@ -105,9 +126,9 @@ func (p *PropertyGenerator) PropertyName() string {
|
|||
return p.Name.LowerName
|
||||
}
|
||||
|
||||
// deserializeFnName returns the identifier of the function that deserializes
|
||||
// DeserializeFnName returns the identifier of the function that deserializes
|
||||
// raw JSON into the generated Go type.
|
||||
func (p *PropertyGenerator) deserializeFnName() string {
|
||||
func (p *PropertyGenerator) DeserializeFnName() string {
|
||||
if p.asIterator {
|
||||
return fmt.Sprintf("%s%s", deserializeIteratorMethod, p.Name.CamelName)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package types
|
||||
package props
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -13,7 +13,7 @@ const (
|
|||
extendedByMethod = "IsExtendedBy"
|
||||
extendsMethod = "Extends"
|
||||
disjointWithMethod = "IsDisjointWith"
|
||||
nameMethod = "Name"
|
||||
typeNameMethod = "Name"
|
||||
serializeMethodName = "Serialize"
|
||||
deserializeFnName = "Deserialize"
|
||||
lessFnName = "Less"
|
||||
|
@ -26,73 +26,34 @@ func TypeInterface(pkg string) *codegen.Interface {
|
|||
comment := fmt.Sprintf("%s represents an ActivityStreams type.", typeInterfaceName)
|
||||
funcs := []codegen.FunctionSignature{
|
||||
{
|
||||
Name: nameMethod,
|
||||
Name: typeNameMethod,
|
||||
Params: nil,
|
||||
Ret: []jen.Code{jen.String()},
|
||||
Comment: fmt.Sprintf("%s returns the ActivityStreams type name.", nameMethod),
|
||||
Comment: fmt.Sprintf("%s returns the ActivityStreams type name.", typeNameMethod),
|
||||
},
|
||||
}
|
||||
return codegen.NewInterface(pkg, typeInterfaceName, funcs, comment)
|
||||
}
|
||||
|
||||
// KindSerializationFuncs returns free function references that can be used to
|
||||
// treat a TypeGenerator as another property's Kind.
|
||||
func KindSerializationFuncs(pkg, typeName string) (ser, deser, less *codegen.Function) {
|
||||
serName := fmt.Sprintf("%s%s", serializeMethodName, typeName)
|
||||
ser = codegen.NewCommentedFunction(
|
||||
pkg,
|
||||
serName,
|
||||
[]jen.Code{jen.Id("s").Id(typeName)},
|
||||
[]jen.Code{jen.Interface(), jen.Error()},
|
||||
[]jen.Code{
|
||||
jen.Return(
|
||||
jen.Id("s").Dot(serializeMethodName).Call(),
|
||||
),
|
||||
},
|
||||
jen.Commentf("%s calls %s on the %s type.", serName, serializeMethodName, typeName))
|
||||
deserName := fmt.Sprintf("%s%s", deserializeFnName, typeName)
|
||||
deser = codegen.NewCommentedFunction(
|
||||
pkg,
|
||||
deserName,
|
||||
[]jen.Code{jen.Id("m").Map(jen.String()).Interface()},
|
||||
[]jen.Code{jen.Op("*").Id(typeName), jen.Error()},
|
||||
[]jen.Code{
|
||||
// TODO
|
||||
},
|
||||
jen.Commentf("%s creates a %s from a map representation that has been unmarshalled from a text or binary format.", deserName, typeName))
|
||||
lessName := fmt.Sprintf("%s%s", lessFnName, typeName)
|
||||
less = codegen.NewCommentedFunction(
|
||||
pkg,
|
||||
lessName,
|
||||
[]jen.Code{
|
||||
jen.Id("i"),
|
||||
jen.Id("j").Op("*").Id(typeName),
|
||||
},
|
||||
[]jen.Code{jen.Bool()},
|
||||
[]jen.Code{
|
||||
// TODO
|
||||
},
|
||||
jen.Commentf("%s computes which %s is lesser, with an arbitrary but stable determination", lessName, typeName))
|
||||
return
|
||||
}
|
||||
|
||||
// Property represents a property of an ActivityStreams type.
|
||||
type Property interface {
|
||||
PropertyName() string
|
||||
StructName() string
|
||||
SetKindFns(name string, ser, deser, less *codegen.Function) error
|
||||
}
|
||||
|
||||
// TypeGenerator represents an ActivityStream type definition to generate in Go.
|
||||
type TypeGenerator struct {
|
||||
packageName string
|
||||
typeName string
|
||||
comment string
|
||||
properties map[string]Property
|
||||
extends []*TypeGenerator
|
||||
disjoint []*TypeGenerator
|
||||
extendedBy []*TypeGenerator
|
||||
cacheOnce sync.Once
|
||||
cachedStruct *codegen.Struct
|
||||
packageName string
|
||||
typeName string
|
||||
comment string
|
||||
properties map[string]Property
|
||||
withoutProperties map[string]Property
|
||||
extends []*TypeGenerator
|
||||
disjoint []*TypeGenerator
|
||||
extendedBy []*TypeGenerator
|
||||
cacheOnce sync.Once
|
||||
cachedStruct *codegen.Struct
|
||||
}
|
||||
|
||||
// NewTypeGenerator creates a new generator for a specific ActivityStreams Core
|
||||
|
@ -105,15 +66,16 @@ type TypeGenerator struct {
|
|||
// All TypeGenerators must be created before the Definition method is called, to
|
||||
// ensure that type extension, in the inheritence sense, is properly set up.
|
||||
func NewTypeGenerator(packageName, typeName, comment string,
|
||||
properties []Property,
|
||||
properties, withoutProperties []Property,
|
||||
extends, disjoint []*TypeGenerator) (*TypeGenerator, error) {
|
||||
t := &TypeGenerator{
|
||||
packageName: packageName,
|
||||
typeName: typeName,
|
||||
comment: comment,
|
||||
properties: make(map[string]Property, len(properties)),
|
||||
extends: extends,
|
||||
disjoint: disjoint,
|
||||
packageName: packageName,
|
||||
typeName: typeName,
|
||||
comment: comment,
|
||||
properties: make(map[string]Property, len(properties)),
|
||||
withoutProperties: make(map[string]Property, len(withoutProperties)),
|
||||
extends: extends,
|
||||
disjoint: disjoint,
|
||||
}
|
||||
for _, property := range properties {
|
||||
if _, has := t.properties[property.PropertyName()]; has {
|
||||
|
@ -121,10 +83,24 @@ func NewTypeGenerator(packageName, typeName, comment string,
|
|||
}
|
||||
t.properties[property.PropertyName()] = property
|
||||
}
|
||||
for _, wop := range withoutProperties {
|
||||
if _, has := t.withoutProperties[wop.PropertyName()]; has {
|
||||
return nil, fmt.Errorf("type already has withoutproperty with name %q", wop.PropertyName())
|
||||
}
|
||||
t.withoutProperties[wop.PropertyName()] = wop
|
||||
}
|
||||
// Complete doubly-linked extends/extendedBy lists.
|
||||
for _, ext := range extends {
|
||||
ext.extendedBy = append(ext.extendedBy, t)
|
||||
}
|
||||
// TODO: Fix: Only notify properties whose Range is this type, not the
|
||||
// properties this type has (which is wrong and currently borken)
|
||||
for _, property := range t.properties {
|
||||
ser, deser, less := t.kindSerializationFuncs()
|
||||
if err := property.SetKindFns(t.TypeName(), ser, deser, less); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
|
@ -167,6 +143,12 @@ func (t *TypeGenerator) Properties() map[string]Property {
|
|||
return t.properties
|
||||
}
|
||||
|
||||
// WithoutProperties returns the properties that do not apply to this type,
|
||||
// mapped by their property name.
|
||||
func (t *TypeGenerator) WithoutProperties() map[string]Property {
|
||||
return t.withoutProperties
|
||||
}
|
||||
|
||||
// extendsFnName determines the name of the Extends function, which
|
||||
// determines if this ActivityStreams type extends another one.
|
||||
func (t *TypeGenerator) extendsFnName() string {
|
||||
|
@ -190,7 +172,7 @@ func (t *TypeGenerator) Definition() *codegen.Struct {
|
|||
t.cacheOnce.Do(func() {
|
||||
members := t.members()
|
||||
m := t.serializationMethod()
|
||||
ser, deser, less := KindSerializationFuncs(t.packageName, t.TypeName())
|
||||
ser, deser, less := t.kindSerializationFuncs()
|
||||
t.cachedStruct = codegen.NewStruct(
|
||||
jen.Commentf(t.Comment()),
|
||||
t.TypeName(),
|
||||
|
@ -211,7 +193,7 @@ func (t *TypeGenerator) Definition() *codegen.Struct {
|
|||
return t.cachedStruct
|
||||
}
|
||||
|
||||
func (t *TypeGenerator) members() (members []jen.Code) {
|
||||
func (t *TypeGenerator) allProperties() map[string]Property {
|
||||
p := t.properties
|
||||
// Properties of parents that are extended, minus DoesNotApplyTo
|
||||
var extends []*TypeGenerator
|
||||
|
@ -220,8 +202,17 @@ func (t *TypeGenerator) members() (members []jen.Code) {
|
|||
for k, v := range ext.Properties() {
|
||||
p[k] = v
|
||||
}
|
||||
// TODO: DoesNotApplyTo
|
||||
}
|
||||
for _, ext := range t.extends {
|
||||
for k, _ := range ext.WithoutProperties() {
|
||||
delete(p, k)
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (t *TypeGenerator) members() (members []jen.Code) {
|
||||
p := t.allProperties()
|
||||
members = make([]jen.Code, 0, len(p))
|
||||
for name, property := range p {
|
||||
members = append(members, jen.Id(strings.Title(name)).Id(property.StructName()))
|
||||
|
@ -234,14 +225,14 @@ func (t *TypeGenerator) members() (members []jen.Code) {
|
|||
func (t *TypeGenerator) nameDefinition() *codegen.Method {
|
||||
return codegen.NewCommentedValueMethod(
|
||||
t.packageName,
|
||||
nameMethod,
|
||||
typeNameMethod,
|
||||
t.TypeName(),
|
||||
/*params=*/ nil,
|
||||
[]jen.Code{jen.String()},
|
||||
[]jen.Code{
|
||||
jen.Return(jen.Lit(t.TypeName())),
|
||||
},
|
||||
jen.Commentf("%s returns the name of this type.", nameMethod))
|
||||
jen.Commentf("%s returns the name of this type.", typeNameMethod))
|
||||
}
|
||||
|
||||
// getAllParentExtends recursively determines all the parent types that this
|
||||
|
@ -275,7 +266,7 @@ func (t *TypeGenerator) extendsDefinition() *codegen.Method {
|
|||
jen.Id("ext"),
|
||||
).Op(":=").Range().Id("extensions")).Block(
|
||||
jen.If(
|
||||
jen.Id("ext").Op("==").Id("other").Dot(nameMethod).Call(),
|
||||
jen.Id("ext").Op("==").Id("other").Dot(typeNameMethod).Call(),
|
||||
).Block(
|
||||
jen.Return(jen.True()),
|
||||
),
|
||||
|
@ -319,7 +310,7 @@ func (t *TypeGenerator) extendedByDefinition() *codegen.Function {
|
|||
jen.Id("ext"),
|
||||
).Op(":=").Range().Id("extensions")).Block(
|
||||
jen.If(
|
||||
jen.Id("ext").Op("==").Id("other").Dot(nameMethod).Call(),
|
||||
jen.Id("ext").Op("==").Id("other").Dot(typeNameMethod).Call(),
|
||||
).Block(
|
||||
jen.Return(jen.True()),
|
||||
),
|
||||
|
@ -363,7 +354,7 @@ func (t *TypeGenerator) disjointWithDefinition() *codegen.Function {
|
|||
jen.Id("disjoint"),
|
||||
).Op(":=").Range().Id("disjointWith")).Block(
|
||||
jen.If(
|
||||
jen.Id("disjoint").Op("==").Id("other").Dot(nameMethod).Call(),
|
||||
jen.Id("disjoint").Op("==").Id("other").Dot(typeNameMethod).Call(),
|
||||
).Block(
|
||||
jen.Return(jen.True()),
|
||||
),
|
||||
|
@ -379,6 +370,8 @@ func (t *TypeGenerator) disjointWithDefinition() *codegen.Function {
|
|||
jen.Commentf("%s returns true if the other provided type is disjoint with the %s type.", t.disjointWithFnName(), t.TypeName()))
|
||||
}
|
||||
|
||||
// serializationMethod returns the method needed to serialize a TypeGenerator as
|
||||
// a property.
|
||||
func (t *TypeGenerator) serializationMethod() (ser *codegen.Method) {
|
||||
ser = codegen.NewCommentedValueMethod(
|
||||
t.packageName,
|
||||
|
@ -388,7 +381,68 @@ func (t *TypeGenerator) serializationMethod() (ser *codegen.Method) {
|
|||
[]jen.Code{jen.Interface(), jen.Error()},
|
||||
[]jen.Code{
|
||||
// TODO
|
||||
jen.Commentf("TODO: Serialization code for %s", t.TypeName()),
|
||||
},
|
||||
jen.Commentf("%s converts this into an interface representation suitable for marshalling into a text or binary format.", serializeMethodName))
|
||||
return
|
||||
}
|
||||
|
||||
// kindSerializationFuncs returns free function references that can be used to
|
||||
// treat a TypeGenerator as another property's Kind.
|
||||
func (t *TypeGenerator) kindSerializationFuncs() (ser, deser, less *codegen.Function) {
|
||||
serName := fmt.Sprintf("%s%s", serializeMethodName, t.TypeName())
|
||||
ser = codegen.NewCommentedFunction(
|
||||
t.packageName,
|
||||
serName,
|
||||
[]jen.Code{jen.Id("s").Id(t.TypeName())},
|
||||
[]jen.Code{jen.Interface(), jen.Error()},
|
||||
[]jen.Code{
|
||||
jen.Return(
|
||||
jen.Id("s").Dot(serializeMethodName).Call(),
|
||||
),
|
||||
},
|
||||
jen.Commentf("%s calls %s on the %s type.", serName, serializeMethodName, t.TypeName()))
|
||||
deserName := fmt.Sprintf("%s%s", deserializeFnName, t.TypeName())
|
||||
deserCode := jen.Empty()
|
||||
for name := range t.allProperties() {
|
||||
deserCode = deserCode.Add(
|
||||
jen.If(
|
||||
jen.List(
|
||||
jen.Id("p"),
|
||||
jen.Err(),
|
||||
// TODO: Qual
|
||||
).Op(":=").Qual("", deserializeFnName).Call(jen.Id("m")),
|
||||
jen.Err().Op("!=").Nil(),
|
||||
).Block(
|
||||
jen.Return(jen.Nil(), jen.Err()),
|
||||
).Else().Block(
|
||||
jen.Id(codegen.This()).Dot(strings.Title(name)).Op(":=").Op("*").Id("p"),
|
||||
))
|
||||
}
|
||||
deser = codegen.NewCommentedFunction(
|
||||
t.packageName,
|
||||
deserName,
|
||||
[]jen.Code{jen.Id("m").Map(jen.String()).Interface()},
|
||||
[]jen.Code{jen.Op("*").Id(t.TypeName()), jen.Error()},
|
||||
[]jen.Code{
|
||||
jen.Id(codegen.This()).Op(":=").Op("&").Id(t.TypeName()).Values(),
|
||||
deserCode,
|
||||
jen.Return(jen.Id(codegen.This()), jen.Nil()),
|
||||
},
|
||||
jen.Commentf("%s creates a %s from a map representation that has been unmarshalled from a text or binary format.", deserName, t.TypeName()))
|
||||
lessName := fmt.Sprintf("%s%s", lessFnName, t.TypeName())
|
||||
less = codegen.NewCommentedFunction(
|
||||
t.packageName,
|
||||
lessName,
|
||||
[]jen.Code{
|
||||
jen.Id("i"),
|
||||
jen.Id("j").Op("*").Id(t.TypeName()),
|
||||
},
|
||||
[]jen.Code{jen.Bool()},
|
||||
[]jen.Code{
|
||||
// TODO
|
||||
jen.Commentf("TODO: Less code for %s", t.TypeName()),
|
||||
},
|
||||
jen.Commentf("%s computes which %s is lesser, with an arbitrary but stable determination", lessName, t.TypeName()))
|
||||
return
|
||||
}
|
読み込み中…
新しいイシューから参照