Clean up qualified names between implementations.

Implementations are relying more on each others' interfaces, which
allows for better code isolation and a better chance at pruning down
binaries when needed. Still plenty of TODO items left to tackle.
このコミットが含まれているのは:
Cory Slep 2018-12-31 18:42:39 +01:00
コミット aeda61d2f1
6個のファイルの変更75行の追加68行の削除

ファイルの表示

@ -202,6 +202,12 @@ func (m Method) Call(on string, params ...jen.Code) jen.Code {
return jen.Id(on).Dot(m.function.name).Call(params...) return jen.Id(on).Dot(m.function.name).Call(params...)
} }
// On generates the Go code that determines the qualified method name on a
// specific variable.
func (m Method) On(on string) *jen.Statement {
return jen.Id(on).Dot(m.function.name)
}
// Name returns the identifier of this function. // Name returns the identifier of this function.
func (m Method) Name() string { func (m Method) Name() string {
return m.function.name return m.function.name

ファイルの表示

@ -282,13 +282,24 @@ func (p *FunctionalPropertyGenerator) serializationFuncs() (*codegen.Method, *co
jen.Id(codegen.This()).Dot(p.isMethodName(i)).Call(), jen.Id(codegen.This()).Dot(p.isMethodName(i)).Call(),
) )
} }
serializeFns = serializeFns.Block( if kind.SerializeFn != nil {
jen.Return( // This is a value that has a function that must be
kind.SerializeFn.Clone().Call( // called to serialize properly.
jen.Id(codegen.This()).Dot(p.getFnName(i)).Call(), serializeFns = serializeFns.Block(
jen.Return(
kind.SerializeFn.Clone().Call(
jen.Id(codegen.This()).Dot(p.getFnName(i)).Call(),
),
), ),
), )
) } else {
// This is a type with a Serialize method.
serializeFns = serializeFns.Block(
jen.Return(
jen.Id(codegen.This()).Dot(p.getFnName(i)).Call().Dot(serializeMethodName).Call(),
),
)
}
} }
serialize := codegen.NewCommentedValueMethod( serialize := codegen.NewCommentedValueMethod(
p.Package.Path(), p.Package.Path(),

ファイルの表示

@ -57,7 +57,8 @@ type ManagerGenerator struct {
// managedMethods caches the specific methods and interfaces mapped to specific // managedMethods caches the specific methods and interfaces mapped to specific
// properties and types. // properties and types.
type managedMethods struct { type managedMethods struct {
deserializor *codegen.Method deserializor *codegen.Method
// TODO: Delete these?
publicDeserializor *codegen.Method publicDeserializor *codegen.Method
// Interface for a manager // Interface for a manager
mIface *codegen.Interface mIface *codegen.Interface
@ -203,6 +204,7 @@ func (m *ManagerGenerator) PrivateManager() *codegen.Struct {
func (m *ManagerGenerator) createPrivateDeserializationMethodForType(tg *TypeGenerator) *codegen.Method { func (m *ManagerGenerator) createPrivateDeserializationMethodForType(tg *TypeGenerator) *codegen.Method {
dn := tg.deserializationFnName() dn := tg.deserializationFnName()
pkg := m.pm.PrivatePackage() pkg := m.pm.PrivatePackage()
// TODO: Better naming scheme from package name
name := fmt.Sprintf("%s%s%s", dn, tg.PrivatePackage().Name(), strings.Title(pkg.Name())) name := fmt.Sprintf("%s%s%s", dn, tg.PrivatePackage().Name(), strings.Title(pkg.Name()))
return codegen.NewCommentedValueMethod( return codegen.NewCommentedValueMethod(
pkg.Path(), pkg.Path(),
@ -233,6 +235,7 @@ func (m *ManagerGenerator) createPrivateDeserializationMethodForType(tg *TypeGen
func (m *ManagerGenerator) createPrivateDeserializationMethodForFuncProperty(fp *FunctionalPropertyGenerator) *codegen.Method { func (m *ManagerGenerator) createPrivateDeserializationMethodForFuncProperty(fp *FunctionalPropertyGenerator) *codegen.Method {
dn := fp.DeserializeFnName() dn := fp.DeserializeFnName()
pkg := m.pm.PrivatePackage() pkg := m.pm.PrivatePackage()
// TODO: Better naming scheme from package name
name := fmt.Sprintf("%s%s%s", dn, fp.Package.Name(), strings.Title(pkg.Name())) name := fmt.Sprintf("%s%s%s", dn, fp.Package.Name(), strings.Title(pkg.Name()))
return codegen.NewCommentedValueMethod( return codegen.NewCommentedValueMethod(
pkg.Path(), pkg.Path(),
@ -263,6 +266,7 @@ func (m *ManagerGenerator) createPrivateDeserializationMethodForFuncProperty(fp
func (m *ManagerGenerator) createPrivateDeserializationMethodForNonFuncProperty(nfp *NonFunctionalPropertyGenerator) *codegen.Method { func (m *ManagerGenerator) createPrivateDeserializationMethodForNonFuncProperty(nfp *NonFunctionalPropertyGenerator) *codegen.Method {
dn := nfp.DeserializeFnName() dn := nfp.DeserializeFnName()
pkg := m.pm.PrivatePackage() pkg := m.pm.PrivatePackage()
// TODO: Better naming scheme from package name
name := fmt.Sprintf("%s%s%s", dn, nfp.Package.Name(), strings.Title(pkg.Name())) name := fmt.Sprintf("%s%s%s", dn, nfp.Package.Name(), strings.Title(pkg.Name()))
return codegen.NewCommentedValueMethod( return codegen.NewCommentedValueMethod(
pkg.Path(), pkg.Path(),

ファイルの表示

@ -156,15 +156,21 @@ func (p *NonFunctionalPropertyGenerator) funcs() []*codegen.Method {
if i > 0 { if i > 0 {
less.Else() less.Else()
} }
// LessFn is nil case -- call Less method directly on the LHS.
lessCall := jen.Id("lhs").Dot(lessMethod).Call(jen.Id("rhs"))
if kind.LessFn != nil {
// LessFn is indeed a function -- call this function
lessCall = kind.LessFn.Clone().Call(
jen.Id("lhs"),
jen.Id("rhs"),
)
}
less.If( less.If(
jen.Id("idx1").Op("==").Lit(i), jen.Id("idx1").Op("==").Lit(i),
).Block( ).Block(
jen.Id("lhs").Op(":=").Id(codegen.This()).Index(jen.Id("i")).Dot(p.getFnName(i)).Call(), jen.Id("lhs").Op(":=").Id(codegen.This()).Index(jen.Id("i")).Dot(p.getFnName(i)).Call(),
jen.Id("rhs").Op(":=").Id(codegen.This()).Index(jen.Id("j")).Dot(p.getFnName(i)).Call(), jen.Id("rhs").Op(":=").Id(codegen.This()).Index(jen.Id("j")).Dot(p.getFnName(i)).Call(),
jen.Return(kind.LessFn.Clone().Call( jen.Return(lessCall),
jen.Id("lhs"),
jen.Id("rhs"),
)),
) )
} }
// Remove Method // Remove Method

ファイルの表示

@ -62,13 +62,15 @@ type Identifier struct {
// Only represents values and other types. // Only represents values and other types.
type Kind struct { type Kind struct {
Name Identifier Name Identifier
// ConcreteKind is expected to be a jen.Qual // ConcreteKind is expected to be properly qualified.
ConcreteKind *jen.Statement ConcreteKind *jen.Statement
Nilable bool Nilable bool
// These functions are expected to be a jen.Qual // Expected to always be non-nil: a function is needed to deserialize.
SerializeFn *jen.Statement
DeserializeFn *jen.Statement DeserializeFn *jen.Statement
LessFn *jen.Statement // If any of these are nil at generation time, assume to call the method
// on the object directly (instead of a qualified function).
SerializeFn *jen.Statement
LessFn *jen.Statement
} }
// PropertyGenerator is a common base struct used in both Functional and // PropertyGenerator is a common base struct used in both Functional and
@ -100,16 +102,14 @@ func (p *PropertyGenerator) GetPackage() Package {
// The name parameter must match the LowerName of an Identifier. // The name parameter must match the LowerName of an Identifier.
// //
// This feels very hacky. // This feels very hacky.
func (p *PropertyGenerator) SetKindFns(name string, qualKind, ser, deser, less *jen.Statement) error { func (p *PropertyGenerator) SetKindFns(name string, qualKind, deser *jen.Statement) error {
for i, kind := range p.Kinds { for i, kind := range p.Kinds {
if kind.Name.LowerName == name { if kind.Name.LowerName == name {
if kind.SerializeFn != nil || kind.DeserializeFn != nil || kind.LessFn != nil { if kind.SerializeFn != nil || kind.DeserializeFn != nil || kind.LessFn != nil {
return fmt.Errorf("property kind already has serialization functions set for %q", name) return fmt.Errorf("property kind already has serialization functions set for %q", name)
} }
kind.ConcreteKind = qualKind kind.ConcreteKind = qualKind
kind.SerializeFn = ser
kind.DeserializeFn = deser kind.DeserializeFn = deser
kind.LessFn = less
p.Kinds[i] = kind p.Kinds[i] = kind
return nil return nil
} }

ファイルの表示

@ -9,9 +9,6 @@ import (
"sync" "sync"
) )
// TODO: Prevent circular dependency by somehow abstracting the requisite
// functions between props and types.
const ( const (
typeInterfaceName = "Type" typeInterfaceName = "Type"
extendedByMethod = "IsExtendedBy" extendedByMethod = "IsExtendedBy"
@ -21,7 +18,7 @@ const (
typeNameMethod = "Name" typeNameMethod = "Name"
serializeMethodName = "Serialize" serializeMethodName = "Serialize"
deserializeFnName = "Deserialize" deserializeFnName = "Deserialize"
lessFnName = "Less" typeLessMethod = "LessThan"
) )
// TypeInterface returns the Type Interface that is needed for ActivityStream // TypeInterface returns the Type Interface that is needed for ActivityStream
@ -45,7 +42,7 @@ type Property interface {
GetPackage() Package GetPackage() Package
PropertyName() string PropertyName() string
StructName() string StructName() string
SetKindFns(name string, kind, ser, deser, less *jen.Statement) error SetKindFns(name string, kind, deser *jen.Statement) error
DeserializeFnName() string DeserializeFnName() string
} }
@ -128,13 +125,12 @@ func NewTypeGenerator(pm *PackageManager, typeName, comment string,
func (t *TypeGenerator) apply(m *ManagerGenerator) error { func (t *TypeGenerator) apply(m *ManagerGenerator) error {
t.m = m t.m = m
// Set up Kind functions // Set up Kind functions
// TODO: Call serialize on an object instead of using a function. // Note: this "i" must be the same as the "i" in the deserialization definition.
ser := jen.Qual(t.PrivatePackage().Path(), t.serializationFnName()) // TODO: Remove this kluge.
deser := jen.Qual(m.privatePackage().Path(), m.getPrivateDeserializationMethodForType(t).Name()) deser := m.getPrivateDeserializationMethodForType(t).On(managerInitName())
less := jen.Qual(t.PrivatePackage().Path(), t.lessFnName())
kind := jen.Qual(t.PublicPackage().Path(), t.InterfaceName()) kind := jen.Qual(t.PublicPackage().Path(), t.InterfaceName())
for _, p := range t.rangeProperties { for _, p := range t.rangeProperties {
if e := p.SetKindFns(t.TypeName(), kind, ser, deser, less); e != nil { if e := p.SetKindFns(t.TypeName(), kind, deser); e != nil {
return e return e
} }
} }
@ -220,17 +216,6 @@ func (t *TypeGenerator) deserializationFnName() string {
return fmt.Sprintf("%s%s", deserializeFnName, t.TypeName()) return fmt.Sprintf("%s%s", deserializeFnName, t.TypeName())
} }
// serializationFnName determines the name of the serialize function for this
// type.
func (t *TypeGenerator) serializationFnName() string {
return fmt.Sprintf("%s%s", serializeMethodName, t.TypeName())
}
// lessFnName determines the name of the less function for this type.
func (t *TypeGenerator) lessFnName() string {
return fmt.Sprintf("%s%s", lessFnName, t.TypeName())
}
// toInterface creates the interface version of the definition generated. // toInterface creates the interface version of the definition generated.
// //
// Requires apply to have already been called. // Requires apply to have already been called.
@ -254,8 +239,9 @@ func (t *TypeGenerator) InterfaceDefinition(pkg Package) *codegen.Interface {
func (t *TypeGenerator) Definition() *codegen.Struct { func (t *TypeGenerator) Definition() *codegen.Struct {
t.cacheOnce.Do(func() { t.cacheOnce.Do(func() {
members := t.members() members := t.members()
m := t.serializationMethod() ser := t.serializationMethod()
ser, deser, less := t.kindSerializationFuncs() less := t.lessMethod()
deser := t.kindDeserializationFunc()
extendsFn, extendsMethod := t.extendsDefinition() extendsFn, extendsMethod := t.extendsDefinition()
t.cachedStruct = codegen.NewStruct( t.cachedStruct = codegen.NewStruct(
jen.Commentf(t.Comments()), jen.Commentf(t.Comments()),
@ -263,15 +249,14 @@ func (t *TypeGenerator) Definition() *codegen.Struct {
[]*codegen.Method{ []*codegen.Method{
t.nameDefinition(), t.nameDefinition(),
extendsMethod, extendsMethod,
m, ser,
less,
}, },
[]*codegen.Function{ []*codegen.Function{
t.extendedByDefinition(), t.extendedByDefinition(),
extendsFn, extendsFn,
t.disjointWithDefinition(), t.disjointWithDefinition(),
ser,
deser, deser,
less,
}, },
members) members)
}) })
@ -322,6 +307,7 @@ func (t *TypeGenerator) members() (members []jen.Code) {
// Convert to jen.Code // Convert to jen.Code
members = make([]jen.Code, 0, len(p)) members = make([]jen.Code, 0, len(p))
for _, property := range sortedMembers { for _, property := range sortedMembers {
// TODO: Use interface instead
members = append(members, jen.Id(strings.Title(property.PropertyName())).Qual(property.GetPackage().Path(), property.StructName())) members = append(members, jen.Id(strings.Title(property.PropertyName())).Qual(property.GetPackage().Path(), property.StructName()))
} }
return return
@ -508,20 +494,27 @@ func (t *TypeGenerator) serializationMethod() (ser *codegen.Method) {
return return
} }
// kindSerializationFuncs returns free function references that can be used to // lessMethod returns the method needed to compare a type with another type.
// treat a TypeGenerator as another property's Kind. func (t *TypeGenerator) lessMethod() (less *codegen.Method) {
func (t *TypeGenerator) kindSerializationFuncs() (ser, deser, less *codegen.Function) { less = codegen.NewCommentedValueMethod(
ser = codegen.NewCommentedFunction(
t.PrivatePackage().Path(), t.PrivatePackage().Path(),
t.serializationFnName(), typeLessMethod,
[]jen.Code{jen.Id("s").Id(t.TypeName())}, t.TypeName(),
[]jen.Code{jen.Interface(), jen.Error()},
[]jen.Code{ []jen.Code{
jen.Return( jen.Id("o").Op("*").Id(t.TypeName()),
jen.Id("s").Dot(serializeMethodName).Call(),
),
}, },
jen.Commentf("%s calls %s on the %s type.", t.serializationFnName(), serializeMethodName, t.TypeName())) []jen.Code{jen.Bool()},
[]jen.Code{
// TODO
jen.Commentf("TODO: Less code for %s", t.TypeName()),
},
jen.Commentf("%s computes if this %s is lesser, with an arbitrary but stable determination", typeLessMethod, t.TypeName()))
return
}
// kindDeserializationFunc returns free function reference that can be used to
// treat a TypeGenerator as another property's Kind.
func (t *TypeGenerator) kindDeserializationFunc() (deser *codegen.Function) {
deserCode := jen.Empty() deserCode := jen.Empty()
for name, prop := range t.allProperties() { for name, prop := range t.allProperties() {
deserMethod := t.m.getPrivateDeserializationMethodForProperty(prop) deserMethod := t.m.getPrivateDeserializationMethodForProperty(prop)
@ -550,18 +543,5 @@ func (t *TypeGenerator) kindSerializationFuncs() (ser, deser, less *codegen.Func
jen.Return(jen.Id(codegen.This()), jen.Nil()), 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.", t.deserializationFnName(), t.TypeName())) jen.Commentf("%s creates a %s from a map representation that has been unmarshalled from a text or binary format.", t.deserializationFnName(), t.TypeName()))
less = codegen.NewCommentedFunction(
t.PrivatePackage().Path(),
t.lessFnName(),
[]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", t.lessFnName(), t.TypeName()))
return return
} }