diff --git a/tools/exp/convert/convert.go b/tools/exp/convert/convert.go index 7159cc7..bc4b976 100644 --- a/tools/exp/convert/convert.go +++ b/tools/exp/convert/convert.go @@ -173,6 +173,12 @@ func (c Converter) convertToFiles(v vocabulary) (f []*File, e error) { Directory: pub.WriteDir(), }) } + propPkgFiles, err := c.propertyPackageFiles(v.FProps, v.NFProps) + if err != nil { + e = err + return + } + f = append(f, propPkgFiles...) // Types for _, i := range v.Types { var pm *props.PackageManager @@ -617,6 +623,45 @@ func (c Converter) typePackageFiles(t map[string]*props.TypeGenerator) (f []*Fil return } +func (c Converter) propertyPackageFiles(fp map[string]*props.FunctionalPropertyGenerator, nfp map[string]*props.NonFunctionalPropertyGenerator) (f []*File, e error) { + switch c.PropertyPackagePolicy { + case PropertyFlatUnderRoot: + fallthrough + case PropertyFlatUnderVocabularyRoot: + // Only need one for all types. + pgs := make([]*props.PropertyGenerator, 0, len(fp)+len(nfp)) + for _, v := range fp { + pgs = append(pgs, &v.PropertyGenerator) + } + for _, v := range nfp { + pgs = append(pgs, &v.PropertyGenerator) + } + ppg := props.NewPropertyPackageGenerator() + // Private + s, i, fn := ppg.PrivateDefinitions(pgs) + priv := pgs[0].GetPrivatePackage() + file := jen.NewFilePath(priv.Path()) + file.Add( + s, + ).Line().Add( + i.Definition(), + ).Line().Add( + fn.Definition(), + ).Line() + f = append(f, &File{ + F: file, + FileName: "gen_pkg.go", + Directory: priv.WriteDir(), + }) + case PropertyIndividualUnderRoot: + // Need individual files per type. + // TODO + default: + e = fmt.Errorf("unrecognized PropertyPackagePolicy: %v", c.PropertyPackagePolicy) + } + return +} + type typeNamer interface { TypeName() string } diff --git a/tools/exp/props/funcprop.go b/tools/exp/props/funcprop.go index 31eb664..b3b8d92 100644 --- a/tools/exp/props/funcprop.go +++ b/tools/exp/props/funcprop.go @@ -321,7 +321,7 @@ func (p *FunctionalPropertyGenerator) serializationFuncs() (*codegen.Method, *co jen.List( jen.Id("v"), jen.Err(), - ).Op(":=").Add(kind.DeserializeFn.Clone().Call( + ).Op(":=").Add(kind.DeserializeFn.Clone().Call().Call( jen.Id("i"), )), jen.Err().Op("!=").Nil(), diff --git a/tools/exp/props/pkg.go b/tools/exp/props/pkg.go index 40548f0..68c867f 100644 --- a/tools/exp/props/pkg.go +++ b/tools/exp/props/pkg.go @@ -148,3 +148,42 @@ func (t *TypePackageGenerator) PrivateDefinitions(tgs []*TypeGenerator) (*jen.St // PropertyPackageGenerator manages generating one-time files needed for // properties. type PropertyPackageGenerator struct{} + +// NewPropertyPackageGenerator creates a new TypePackageGenerator. +func NewPropertyPackageGenerator() *PropertyPackageGenerator { + return &PropertyPackageGenerator{} +} + +// PrivateDefinitions creates the private code generated definitions needed once +// per package. +// +// Precondition: The passed-in generators are the complete set of type +// generators within a package. +func (p *PropertyPackageGenerator) PrivateDefinitions(pgs []*PropertyGenerator) (*jen.Statement, *codegen.Interface, *codegen.Function) { + fnsMap := make(map[string]codegen.FunctionSignature) + for _, pg := range pgs { + for _, m := range pg.getAllManagerMethods() { + v := m.ToFunctionSignature() + fnsMap[v.Name] = v + } + } + var fns []codegen.FunctionSignature + for _, v := range fnsMap { + fns = append(fns, v) + } + return jen.Var().Id(managerInitName()).Id(managerInterfaceName), + codegen.NewInterface(pgs[0].GetPrivatePackage().Path(), + managerInterfaceName, + fns, + fmt.Sprintf("%s abstracts the code-generated manager that provides access to concrete implementations.", managerInterfaceName)), + codegen.NewCommentedFunction(pgs[0].GetPrivatePackage().Path(), + setManagerFunctionName, + []jen.Code{ + jen.Id("m").Id(managerInterfaceName), + }, + /*ret=*/ nil, + []jen.Code{ + jen.Id(managerInitName()).Op("=").Id("m"), + }, + jen.Commentf("%s sets the manager package-global variable. For internal use only, do not use as part of Application behavior. Must be called at golang init time.", setManagerFunctionName)) +} diff --git a/tools/exp/props/property.go b/tools/exp/props/property.go index 249a2de..1d2bb93 100644 --- a/tools/exp/props/property.go +++ b/tools/exp/props/property.go @@ -105,7 +105,8 @@ func (k Kind) lessFnCode(this, other *jen.Statement) *jen.Statement { // // TODO: Make this type private type PropertyGenerator struct { - vocabName string + vocabName string + managerMethods []*codegen.Method // TODO: Make these private PackageManager *PackageManager Name Identifier @@ -136,14 +137,15 @@ func (p *PropertyGenerator) GetPublicPackage() Package { // The name parameter must match the LowerName of an Identifier. // // This feels very hacky. -func (p *PropertyGenerator) SetKindFns(name string, qualKind, deser *jen.Statement) error { +func (p *PropertyGenerator) SetKindFns(name string, qualKind *jen.Statement, deser *codegen.Method) error { for i, 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.ConcreteKind = qualKind - kind.DeserializeFn = deser + kind.DeserializeFn = deser.On(managerInitName()) + p.managerMethods = append(p.managerMethods, deser) p.Kinds[i] = kind return nil } @@ -151,6 +153,12 @@ func (p *PropertyGenerator) SetKindFns(name string, qualKind, deser *jen.Stateme return fmt.Errorf("cannot find property kind %q", name) } +// getAllManagerMethods returns the list of manager methods used by this +// property. +func (p *PropertyGenerator) getAllManagerMethods() []*codegen.Method { + return p.managerMethods +} + // StructName returns the name of the type, which may or may not be a struct, // to generate. func (p *PropertyGenerator) StructName() string { diff --git a/tools/exp/props/type.go b/tools/exp/props/type.go index 27e766e..6eb4a19 100644 --- a/tools/exp/props/type.go +++ b/tools/exp/props/type.go @@ -44,7 +44,7 @@ type Property interface { GetPublicPackage() Package PropertyName() string InterfaceName() string - SetKindFns(name string, kind, deser *jen.Statement) error + SetKindFns(name string, kind *jen.Statement, deser *codegen.Method) error DeserializeFnName() string } @@ -130,8 +130,8 @@ func (t *TypeGenerator) apply(m *ManagerGenerator) error { t.m = m // Set up Kind functions // Note: this "i" must be the same as the "i" in the deserialization definition. - // TODO: Remove this kluge. - deser := m.getDeserializationMethodForType(t).On(managerInitName()) + // TODO: Remove this kluge. (2nd todo: figure out wtf this todo means) + deser := m.getDeserializationMethodForType(t) kind := jen.Qual(t.PublicPackage().Path(), t.InterfaceName()) for _, p := range t.rangeProperties { if e := p.SetKindFns(t.TypeName(), kind, deser); e != nil {