Overhaul package management, add manager.

The manager class will be responsible for allowing the generated code to
be compilable while also permitting types and properties to be isolated,
such that binaries can be pruned to smaller sizes and not require the
entire gambit be built into the resulting executable.

This state will successfully generate code, but the generated code is
completely uncompilable. It will also trash the props/ directory.
このコミットが含まれているのは:
Cory Slep 2018-12-30 16:09:14 +01:00
コミット ce699464bf
12個のファイルの変更804行の追加340行の削除

ファイルの表示

@ -206,3 +206,12 @@ func (m Method) Call(on string, params ...jen.Code) jen.Code {
func (m Method) Name() string {
return m.function.name
}
// ToFunctionSignature obtains this method's FunctionSignature.
func (m Method) ToFunctionSignature() FunctionSignature {
return FunctionSignature{
Name: m.Name(),
Params: m.function.params,
Ret: m.function.ret,
}
}

ファイルの表示

@ -78,3 +78,12 @@ func (s *Struct) Method(name string) *Method {
func (s *Struct) Constructors(name string) *Function {
return s.constructors[name]
}
// ToInterface creates an interface version of this struct.
func (s *Struct) ToInterface(pkg, name, comment string) *Interface {
fns := make([]FunctionSignature, 0, len(s.methods))
for _, m := range s.methods {
fns = append(fns, m.ToFunctionSignature())
}
return NewInterface(pkg, name, fns, comment)
}

ファイルの表示

@ -66,3 +66,12 @@ func (t *Typedef) Method(name string) *Method {
func (t *Typedef) Constructors(name string) *Function {
return t.constructors[name]
}
// ToInterface creates an interface version of this typedef.
func (t *Typedef) ToInterface(pkg, name, comment string) *Interface {
fns := make([]FunctionSignature, 0, len(t.methods))
for _, m := range t.methods {
fns = append(fns, m.ToFunctionSignature())
}
return NewInterface(pkg, name, fns, comment)
}

ファイルの表示

@ -19,6 +19,7 @@ type vocabulary struct {
FProps map[string]*props.FunctionalPropertyGenerator
NFProps map[string]*props.NonFunctionalPropertyGenerator
Types map[string]*props.TypeGenerator
Manager *props.ManagerGenerator
}
func newVocabulary() vocabulary {
@ -30,6 +31,30 @@ func newVocabulary() vocabulary {
}
}
func (v vocabulary) typeArray() []*props.TypeGenerator {
tg := make([]*props.TypeGenerator, 0, len(v.Types))
for _, t := range v.Types {
tg = append(tg, t)
}
return tg
}
func (v vocabulary) funcPropArray() []*props.FunctionalPropertyGenerator {
fp := make([]*props.FunctionalPropertyGenerator, 0, len(v.FProps))
for _, f := range v.FProps {
fp = append(fp, f)
}
return fp
}
func (v vocabulary) nonFuncPropArray() []*props.NonFunctionalPropertyGenerator {
nfp := make([]*props.NonFunctionalPropertyGenerator, 0, len(v.NFProps))
for _, nf := range v.NFProps {
nfp = append(nfp, nf)
}
return nfp
}
type PropertyPackagePolicy int
const (
@ -48,11 +73,11 @@ const (
type Converter struct {
Registry *rdf.RDFRegistry
VocabularyRoot string
VocabularyRoot *props.PackageManager
PropertyPackagePolicy PropertyPackagePolicy
PropertyPackageRoot string
PropertyPackageRoot *props.PackageManager
TypePackagePolicy TypePackagePolicy
TypePackageRoot string
TypePackageRoot *props.PackageManager
}
func (c Converter) Convert(p *rdf.ParsedVocabulary) (f []*File, e error) {
@ -70,17 +95,13 @@ func (c Converter) convertToFiles(v vocabulary) (f []*File, e error) {
// TODO: Implement
}
for _, i := range v.FProps {
var pkg string
pkg, e = c.propertyPackageFile(i)
var pm *props.PackageManager
pm, e = c.propertyPackageManager(i)
if e != nil {
return
}
var dir string
dir, e = c.propertyPackageDirectory(i)
if e != nil {
return
}
file := jen.NewFilePath(pkg)
dir := pm.PrivatePackage().Path()
file := jen.NewFilePath(dir)
file.Add(i.Definition().Definition())
f = append(f, &File{
F: file,
@ -89,17 +110,13 @@ func (c Converter) convertToFiles(v vocabulary) (f []*File, e error) {
})
}
for _, i := range v.NFProps {
var pkg string
pkg, e = c.propertyPackageFile(i)
var pm *props.PackageManager
pm, e = c.propertyPackageManager(i)
if e != nil {
return
}
var dir string
dir, e = c.propertyPackageDirectory(i)
if e != nil {
return
}
file := jen.NewFilePath(pkg)
dir := pm.PrivatePackage().Path()
file := jen.NewFilePath(dir)
s, t := i.Definitions()
file.Add(s.Definition()).Line().Add(t.Definition())
f = append(f, &File{
@ -109,17 +126,13 @@ func (c Converter) convertToFiles(v vocabulary) (f []*File, e error) {
})
}
for _, i := range v.Types {
var pkg string
pkg, e = c.typePackageFile(i)
var pm *props.PackageManager
pm, e = c.typePackageManager(i)
if e != nil {
return
}
var dir string
dir, e = c.typePackageDirectory(i)
if e != nil {
return
}
file := jen.NewFilePath(pkg)
dir := pm.PrivatePackage().Path()
file := jen.NewFilePath(dir)
file.Add(i.Definition().Definition())
f = append(f, &File{
F: file,
@ -127,6 +140,15 @@ func (c Converter) convertToFiles(v vocabulary) (f []*File, e error) {
Directory: dir,
})
}
// TODO: For Manager
dir := c.VocabularyRoot.PrivatePackage().Path()
file := jen.NewFilePath(dir)
file.Add(v.Manager.PrivateManager().Definition())
f = append(f, &File{
F: file,
FileName: "gen_manager.go",
Directory: dir,
})
return
}
@ -186,6 +208,11 @@ func (c Converter) convertVocabulary(p *rdf.ParsedVocabulary) (v vocabulary, e e
return
}
}
v.Manager, e = props.NewManagerGenerator(
*c.VocabularyRoot,
v.typeArray(),
v.funcPropArray(),
v.nonFuncPropArray())
return
}
@ -195,11 +222,12 @@ func (c Converter) convertType(t rdf.VocabularyType,
existingNFProps map[string]*props.NonFunctionalPropertyGenerator,
existingTypes map[string]*props.TypeGenerator) (tg *props.TypeGenerator, e error) {
// Determine the props package name
var pkg string
pkg, e = c.typePackageName(t)
var pm *props.PackageManager
pm, e = c.typePackageManager(t)
if e != nil {
return
}
pkg := pm.PrivatePackage()
// Determine the properties for this type
var p []props.Property
for _, prop := range t.Properties {
@ -251,60 +279,48 @@ func (c Converter) convertType(t rdf.VocabularyType,
ext = append(ext, existingTypes[ex.Name])
}
}
tg, e = props.NewTypeGenerator(
pkg,
c.convertTypeToName(t),
t.Notes,
p,
wop,
ext,
nil)
if e != nil {
return
}
// Apply disjoint if both sides are available because the TypeGenerator
// does not know the entire vocabulary, so cannot do this lookup and
// create this connection for us.
//
// TODO: Pass in the disjoint and have the TypeGenerator complete the
// doubly-linked connection for us.
var disjoint []*props.TypeGenerator
for _, disj := range t.DisjointWith {
if len(disj.Vocab) != 0 {
// 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 {
disjointType.AddDisjoint(tg)
tg.AddDisjoint(disjointType)
disjoint = append(disjoint, disjointType)
}
}
// Apply the type's KindSerializationFuncs to the property because there
// is no way for the TypeGenerator to know all properties who have a
// range of this type.
// Pass in properties whose range is this type so it can build
// references properly.
//
// TODO: Pass in these properties to the TypeGenerator constructor so it
// can build these double-links properly. Note this would also need to
// apply to referenced properties, possibly.
// TODO: Enable this for referenced properties.
name := c.convertTypeToName(t)
var rangeProps []props.Property
for _, prop := range existingFProps {
for _, kind := range prop.Kinds {
if kind.Name.LowerName == tg.TypeName() {
ser, deser, less := tg.KindSerializationFuncs()
if e = prop.SetKindFns(tg.TypeName(), ser, deser, less); e != nil {
return
}
if kind.Name.LowerName == name {
rangeProps = append(rangeProps, prop)
}
}
}
for _, prop := range existingNFProps {
for _, kind := range prop.Kinds {
if kind.Name.LowerName == tg.TypeName() {
ser, deser, less := tg.KindSerializationFuncs()
if e = prop.SetKindFns(tg.TypeName(), ser, deser, less); e != nil {
return
}
if kind.Name.LowerName == name {
rangeProps = append(rangeProps, prop)
}
}
}
tg, e = props.NewTypeGenerator(
pkg,
name,
t.Notes,
p,
wop,
rangeProps,
ext,
disjoint)
return
}
@ -317,11 +333,12 @@ func (c Converter) convertFunctionalProperty(p rdf.VocabularyProperty,
if e != nil {
return
}
var pkg string
pkg, e = c.propertyPackageName(p)
var pm *props.PackageManager
pm, e = c.propertyPackageManager(p)
if e != nil {
return
}
pkg := pm.PrivatePackage()
fp = props.NewFunctionalPropertyGenerator(
pkg,
c.toIdentifier(p),
@ -339,11 +356,12 @@ func (c Converter) convertNonFunctionalProperty(p rdf.VocabularyProperty,
if e != nil {
return
}
var pkg string
pkg, e = c.propertyPackageName(p)
var pm *props.PackageManager
pm, e = c.propertyPackageManager(p)
if e != nil {
return
}
pkg := pm.PrivatePackage()
nfp = props.NewNonFunctionalPropertyGenerator(
pkg,
c.toIdentifier(p),
@ -357,9 +375,10 @@ func (c Converter) convertValue(v rdf.VocabularyValue) (k *props.Kind) {
Name: c.toIdentifier(v),
ConcreteKind: v.DefinitionType,
Nilable: c.isNilable(v.DefinitionType),
SerializeFn: v.SerializeFn,
DeserializeFn: v.DeserializeFn,
LessFn: v.LessFn,
// TODO
SerializeFn: jen.Empty().Add(v.SerializeFn.Call()),
DeserializeFn: jen.Empty().Add(v.DeserializeFn.Call()),
LessFn: jen.Empty().Add(v.LessFn.Call()),
}
return
}
@ -445,12 +464,12 @@ func (c Converter) propertyKinds(v rdf.VocabularyProperty,
return
}
func (c Converter) typePackageName(v rdf.VocabularyType) (pkg string, e error) {
func (c Converter) typePackageManager(v typeNamer) (pkg *props.PackageManager, e error) {
switch c.TypePackagePolicy {
case TypeFlatUnderRoot:
pkg = c.TypePackageRoot
case TypeIndividualUnderRoot:
pkg = v.Name
pkg = c.TypePackageRoot.Sub(v.TypeName())
case TypeFlatUnderVocabularyRoot:
pkg = c.VocabularyRoot
default:
@ -459,12 +478,12 @@ func (c Converter) typePackageName(v rdf.VocabularyType) (pkg string, e error) {
return
}
func (c Converter) propertyPackageName(v rdf.VocabularyProperty) (pkg string, e error) {
func (c Converter) propertyPackageManager(v propertyNamer) (pkg *props.PackageManager, e error) {
switch c.PropertyPackagePolicy {
case PropertyFlatUnderRoot:
pkg = c.PropertyPackageRoot
case PropertyIndividualUnderRoot:
pkg = v.Name
pkg = c.PropertyPackageRoot.Sub(v.PropertyName())
case PropertyFlatUnderVocabularyRoot:
pkg = c.VocabularyRoot
default:
@ -473,33 +492,14 @@ func (c Converter) propertyPackageName(v rdf.VocabularyProperty) (pkg string, e
return
}
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)
case TypeIndividualUnderRoot:
dir = fmt.Sprintf("%s/%s/%s/", c.VocabularyRoot, c.TypePackageRoot, v.TypeName())
case TypeFlatUnderVocabularyRoot:
dir = c.VocabularyRoot + "/"
default:
e = fmt.Errorf("unrecognized TypePackagePolicy: %v", c.TypePackagePolicy)
}
return
type typeNamer interface {
TypeName() string
}
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)
case TypeIndividualUnderRoot:
pkg = fmt.Sprintf("%s/%s/%s", c.VocabularyRoot, c.TypePackageRoot, v.TypeName())
case TypeFlatUnderVocabularyRoot:
pkg = c.VocabularyRoot
default:
e = fmt.Errorf("unrecognized TypePackagePolicy: %v", c.TypePackagePolicy)
}
return
}
var (
_ typeNamer = &props.TypeGenerator{}
_ typeNamer = &rdf.VocabularyType{}
)
type propertyNamer interface {
PropertyName() string
@ -508,36 +508,9 @@ type propertyNamer interface {
var (
_ propertyNamer = &props.FunctionalPropertyGenerator{}
_ propertyNamer = &props.NonFunctionalPropertyGenerator{}
_ propertyNamer = &rdf.VocabularyProperty{}
)
func (c Converter) propertyPackageDirectory(v propertyNamer) (dir string, e error) {
switch c.PropertyPackagePolicy {
case PropertyFlatUnderRoot:
dir = fmt.Sprintf("%s/%s/", c.VocabularyRoot, c.PropertyPackageRoot)
case PropertyIndividualUnderRoot:
dir = fmt.Sprintf("%s/%s/%s/", c.VocabularyRoot, c.PropertyPackageRoot, v.PropertyName())
case PropertyFlatUnderVocabularyRoot:
dir = c.VocabularyRoot + "/"
default:
e = fmt.Errorf("unrecognized PropertyPackagePolicy: %v", c.PropertyPackagePolicy)
}
return
}
func (c Converter) propertyPackageFile(v propertyNamer) (pkg string, e error) {
switch c.PropertyPackagePolicy {
case PropertyFlatUnderRoot:
pkg = fmt.Sprintf("%s/%s", c.VocabularyRoot, c.PropertyPackageRoot)
case PropertyIndividualUnderRoot:
pkg = fmt.Sprintf("%s/%s/%s", c.VocabularyRoot, c.PropertyPackageRoot, v.PropertyName())
case PropertyFlatUnderVocabularyRoot:
pkg = c.VocabularyRoot
default:
e = fmt.Errorf("unrecognized PropertyPackagePolicy: %v", c.PropertyPackagePolicy)
}
return
}
func (c Converter) toIdentifier(n rdf.NameGetter) props.Identifier {
return props.Identifier{
LowerName: n.GetName(),

ファイルの表示

@ -6,6 +6,7 @@ import (
"fmt"
"github.com/cjslep/activity/tools/exp/convert"
"github.com/cjslep/activity/tools/exp/rdf"
"github.com/cjslep/activity/tools/exp/props"
"github.com/cjslep/activity/tools/exp/rdf/owl"
"github.com/cjslep/activity/tools/exp/rdf/rdfs"
"github.com/cjslep/activity/tools/exp/rdf/schema"
@ -81,11 +82,11 @@ func main() {
}
c := &convert.Converter{
Registry: registry,
VocabularyRoot: "as",
VocabularyRoot: props.NewPackageManager("as"),
PropertyPackagePolicy: convert.PropertyFlatUnderRoot,
PropertyPackageRoot: "props",
PropertyPackageRoot: props.NewPackageManager("props"),
TypePackagePolicy: convert.TypeFlatUnderRoot,
TypePackageRoot: "types",
TypePackageRoot: props.NewPackageManager("types"),
}
f, err := c.Convert(p)
if err != nil {

ファイルの表示

@ -19,7 +19,10 @@ type FunctionalPropertyGenerator struct {
// NewFunctionalPropertyGenerator is a convenience constructor to create
// FunctionalPropertyGenerators.
func NewFunctionalPropertyGenerator(pkg string,
//
// PropertyGenerators shoulf be in the first pass to construct, before types and
// other generators are constructed.
func NewFunctionalPropertyGenerator(pkg Package,
name Identifier,
kinds []Kind,
hasNaturalLanguageMap bool) *FunctionalPropertyGenerator {
@ -33,6 +36,12 @@ func NewFunctionalPropertyGenerator(pkg string,
}
}
// toInterface creates the interface version of the definition generated.
func (p *FunctionalPropertyGenerator) toInterface(pkg Package) *codegen.Interface {
s := p.Definition()
return s.ToInterface(pkg.Path(), p.InterfaceName(), "")
}
// isSingleTypeDef determines whether a special-case API can be generated for
// one allowed Kind.
func (p *FunctionalPropertyGenerator) isSingleTypeDef() bool {
@ -113,7 +122,7 @@ func (p *FunctionalPropertyGenerator) funcs() []*codegen.Method {
}
methods := []*codegen.Method{
codegen.NewCommentedValueMethod(
p.PackageName(),
p.Package.Path(),
kindIndexMethod,
p.StructName(),
/*params=*/ nil,
@ -129,7 +138,7 @@ func (p *FunctionalPropertyGenerator) funcs() []*codegen.Method {
// IsLanguageMap Method
methods = append(methods,
codegen.NewCommentedValueMethod(
p.PackageName(),
p.Package.Path(),
isLanguageMapMethod,
p.StructName(),
/*params=*/ nil,
@ -154,7 +163,7 @@ func (p *FunctionalPropertyGenerator) funcs() []*codegen.Method {
// HasLanguage Method
methods = append(methods,
codegen.NewCommentedValueMethod(
p.PackageName(),
p.Package.Path(),
hasLanguageMethod,
p.StructName(),
[]jen.Code{jen.Id("bcp47").String()},
@ -182,7 +191,7 @@ func (p *FunctionalPropertyGenerator) funcs() []*codegen.Method {
// GetLanguage Method
methods = append(methods,
codegen.NewCommentedValueMethod(
p.PackageName(),
p.Package.Path(),
getLanguageMethod,
p.StructName(),
[]jen.Code{jen.Id("bcp47").String()},
@ -214,7 +223,7 @@ func (p *FunctionalPropertyGenerator) funcs() []*codegen.Method {
// SetLanguage Method
methods = append(methods,
codegen.NewCommentedPointerMethod(
p.PackageName(),
p.Package.Path(),
setLanguageMethod,
p.StructName(),
[]jen.Code{
@ -248,7 +257,7 @@ func (p *FunctionalPropertyGenerator) funcs() []*codegen.Method {
// serializationFuncs produces the Methods and Functions needed for a
// functional property to be serialized and deserialized to and from an
// encoding.
func (p *FunctionalPropertyGenerator) serializationFuncs() ([]*codegen.Method, []*codegen.Function) {
func (p *FunctionalPropertyGenerator) serializationFuncs() (*codegen.Method, *codegen.Function) {
serializeFns := jen.Empty()
for i, kind := range p.Kinds {
if i > 0 {
@ -271,20 +280,17 @@ func (p *FunctionalPropertyGenerator) serializationFuncs() ([]*codegen.Method, [
),
)
}
serialize := []*codegen.Method{
codegen.NewCommentedValueMethod(
p.PackageName(),
p.serializeFnName(),
p.StructName(),
/*params=*/ nil,
[]jen.Code{jen.Interface(), jen.Error()},
[]jen.Code{serializeFns, jen.Return(
jen.Id(codegen.This()).Dot(unknownMemberName),
jen.Nil(),
)},
jen.Commentf("%s converts this into an interface representation suitable for marshalling into a text or binary format.", p.serializeFnName()),
),
}
serialize := codegen.NewCommentedValueMethod(
p.Package.Path(),
p.serializeFnName(),
p.StructName(),
/*params=*/ nil,
[]jen.Code{jen.Interface(), jen.Error()},
[]jen.Code{serializeFns, jen.Return(
jen.Id(codegen.This()).Dot(unknownMemberName),
jen.Nil(),
)},
jen.Commentf("%s converts this into an interface representation suitable for marshalling into a text or binary format.", p.serializeFnName()))
deserializeFns := jen.Empty()
for i, kind := range p.Kinds {
if i > 0 {
@ -315,49 +321,45 @@ func (p *FunctionalPropertyGenerator) serializationFuncs() ([]*codegen.Method, [
),
)
}
var deserialize []*codegen.Function
var deserialize *codegen.Function
if p.asIterator {
deserialize = append(deserialize,
codegen.NewCommentedFunction(
p.PackageName(),
p.DeserializeFnName(),
[]jen.Code{jen.Id("i").Interface()},
[]jen.Code{jen.Op("*").Id(p.StructName()), jen.Error()},
[]jen.Code{
p.addUnknownDeserializeCode(deserializeFns),
jen.Return(
jen.Nil(),
jen.Nil(),
),
},
jen.Commentf("%s creates an iterator from an element that has been unmarshalled from a text or binary format.", p.DeserializeFnName()),
))
deserialize = codegen.NewCommentedFunction(
p.Package.Path(),
p.DeserializeFnName(),
[]jen.Code{jen.Id("i").Interface()},
[]jen.Code{jen.Op("*").Id(p.StructName()), jen.Error()},
[]jen.Code{
p.addUnknownDeserializeCode(deserializeFns),
jen.Return(
jen.Nil(),
jen.Nil(),
),
},
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(),
[]jen.Code{jen.Id("m").Map(jen.String()).Interface()},
[]jen.Code{jen.Op("*").Id(p.StructName()), jen.Error()},
[]jen.Code{
jen.If(
jen.List(
jen.Id("i"),
jen.Id("ok"),
).Op(":=").Id("m").Index(
jen.Lit(p.PropertyName()),
),
deserialize = codegen.NewCommentedFunction(
p.Package.Path(),
p.DeserializeFnName(),
[]jen.Code{jen.Id("m").Map(jen.String()).Interface()},
[]jen.Code{jen.Op("*").Id(p.StructName()), jen.Error()},
[]jen.Code{
jen.If(
jen.List(
jen.Id("i"),
jen.Id("ok"),
).Block(
p.addUnknownDeserializeCode(deserializeFns),
).Op(":=").Id("m").Index(
jen.Lit(p.PropertyName()),
),
jen.Return(
jen.Nil(),
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.Id("ok"),
).Block(
p.addUnknownDeserializeCode(deserializeFns),
),
jen.Return(
jen.Nil(),
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()))
}
return serialize, deserialize
}
@ -389,7 +391,11 @@ func (p *FunctionalPropertyGenerator) singleTypeDef() *codegen.Struct {
if p.HasNaturalLanguageMap {
kindMembers = append(kindMembers, jen.Id(langMapMember).Map(jen.String()).String())
}
methods, funcs := p.serializationFuncs()
var methods []*codegen.Method
var funcs []*codegen.Function
ser, deser := p.serializationFuncs()
methods = append(methods, ser)
funcs = append(funcs, deser)
methods = append(methods, p.singleTypeFuncs()...)
methods = append(methods, p.funcs()...)
methods = append(methods, p.commonMethods()...)
@ -421,7 +427,7 @@ func (p *FunctionalPropertyGenerator) singleTypeFuncs() []*codegen.Method {
}
if p.Kinds[0].Nilable {
methods = append(methods, codegen.NewCommentedValueMethod(
p.PackageName(),
p.Package.Path(),
hasMethod,
p.StructName(),
/*params=*/ nil,
@ -431,7 +437,7 @@ func (p *FunctionalPropertyGenerator) singleTypeFuncs() []*codegen.Method {
))
} else {
methods = append(methods, codegen.NewCommentedValueMethod(
p.PackageName(),
p.Package.Path(),
hasMethod,
p.StructName(),
/*params=*/ nil,
@ -443,7 +449,7 @@ func (p *FunctionalPropertyGenerator) singleTypeFuncs() []*codegen.Method {
// Get Method
getComment := jen.Commentf("%s returns the value of this property. When %s returns false, %s will return any arbitrary value.", getMethod, hasMethod, getMethod)
methods = append(methods, codegen.NewCommentedValueMethod(
p.PackageName(),
p.Package.Path(),
p.getFnName(0),
p.StructName(),
/*params=*/ nil,
@ -465,7 +471,7 @@ func (p *FunctionalPropertyGenerator) singleTypeFuncs() []*codegen.Method {
}
if p.Kinds[0].Nilable {
methods = append(methods, codegen.NewCommentedPointerMethod(
p.PackageName(),
p.Package.Path(),
p.setFnName(0),
p.StructName(),
[]jen.Code{jen.Id("v").Id(p.Kinds[0].ConcreteKind)},
@ -478,7 +484,7 @@ func (p *FunctionalPropertyGenerator) singleTypeFuncs() []*codegen.Method {
))
} else {
methods = append(methods, codegen.NewCommentedPointerMethod(
p.PackageName(),
p.Package.Path(),
p.setFnName(0),
p.StructName(),
[]jen.Code{jen.Id("v").Id(p.Kinds[0].ConcreteKind)},
@ -507,7 +513,7 @@ func (p *FunctionalPropertyGenerator) singleTypeFuncs() []*codegen.Method {
}
if p.Kinds[0].Nilable {
methods = append(methods, codegen.NewCommentedPointerMethod(
p.PackageName(),
p.Package.Path(),
p.clearMethodName(),
p.StructName(),
/*params=*/ nil,
@ -517,7 +523,7 @@ func (p *FunctionalPropertyGenerator) singleTypeFuncs() []*codegen.Method {
))
} else {
methods = append(methods, codegen.NewCommentedPointerMethod(
p.PackageName(),
p.Package.Path(),
p.clearMethodName(),
p.StructName(),
/*params=*/ nil,
@ -562,7 +568,11 @@ func (p *FunctionalPropertyGenerator) multiTypeDef() *codegen.Struct {
"%s is an iterator for a property. It is permitted to be one of multiple value types.", p.StructName(),
).Line().Comment("").Line().Add(explanation)
}
methods, funcs := p.serializationFuncs()
var methods []*codegen.Method
var funcs []*codegen.Function
ser, deser := p.serializationFuncs()
methods = append(methods, ser)
funcs = append(funcs, deser)
methods = append(methods, p.multiTypeFuncs()...)
methods = append(methods, p.funcs()...)
methods = append(methods, p.commonMethods()...)
@ -602,7 +612,7 @@ func (p *FunctionalPropertyGenerator) multiTypeFuncs() []*codegen.Method {
)
}
methods = append(methods, codegen.NewCommentedPointerMethod(
p.PackageName(),
p.Package.Path(),
hasAnyMethodName,
p.StructName(),
/*params=*/ nil,
@ -626,7 +636,7 @@ func (p *FunctionalPropertyGenerator) multiTypeFuncs() []*codegen.Method {
clearLine = append(clearLine, jen.Id(codegen.This()).Dot(langMapMember).Op("=").Nil())
}
methods = append(methods, codegen.NewCommentedPointerMethod(
p.PackageName(),
p.Package.Path(),
p.clearMethodName(),
p.StructName(),
/*params=*/ nil,
@ -649,7 +659,7 @@ func (p *FunctionalPropertyGenerator) multiTypeFuncs() []*codegen.Method {
}
if kind.Nilable {
methods = append(methods, codegen.NewCommentedValueMethod(
p.PackageName(),
p.Package.Path(),
p.isMethodName(i),
p.StructName(),
/*params=*/ nil,
@ -659,7 +669,7 @@ func (p *FunctionalPropertyGenerator) multiTypeFuncs() []*codegen.Method {
))
} else {
methods = append(methods, codegen.NewCommentedValueMethod(
p.PackageName(),
p.Package.Path(),
p.isMethodName(i),
p.StructName(),
/*params=*/ nil,
@ -684,7 +694,7 @@ func (p *FunctionalPropertyGenerator) multiTypeFuncs() []*codegen.Method {
}
if kind.Nilable {
methods = append(methods, codegen.NewCommentedPointerMethod(
p.PackageName(),
p.Package.Path(),
p.setFnName(i),
p.StructName(),
[]jen.Code{jen.Id("v").Id(kind.ConcreteKind)},
@ -697,7 +707,7 @@ func (p *FunctionalPropertyGenerator) multiTypeFuncs() []*codegen.Method {
))
} else {
methods = append(methods, codegen.NewCommentedPointerMethod(
p.PackageName(),
p.Package.Path(),
p.setFnName(i),
p.StructName(),
[]jen.Code{jen.Id("v").Id(kind.ConcreteKind)},
@ -715,7 +725,7 @@ func (p *FunctionalPropertyGenerator) multiTypeFuncs() []*codegen.Method {
for i, kind := range p.Kinds {
getComment := jen.Commentf("%s returns the value of this property. When %s returns false, %s will return an arbitrary value.", p.getFnName(i), p.isMethodName(i), p.getFnName(i))
methods = append(methods, codegen.NewCommentedValueMethod(
p.PackageName(),
p.Package.Path(),
p.getFnName(i),
p.StructName(),
/*params=*/ nil,

289
tools/exp/props/manager.go ノーマルファイル
ファイルの表示

@ -0,0 +1,289 @@
package props
import (
"fmt"
"github.com/cjslep/activity/tools/exp/codegen"
"github.com/dave/jennifer/jen"
"strings"
"sync"
)
const (
managerName = "ASManager"
managerInitVarName = "mgr"
)
func managerInitName() string {
return managerInitVarName
}
// Generates the ActivityStreamManager that handles the static and/or dynamic
// loading of ActivityStream Core, Extended, and any extension types.
//
// This also provides interfaces to break the recursive/cyclic dependencies
// between properties and types. The previous version of this tool did not
// attempt to solve this problem, and instead just created one big and bloated
// library in order to avoid having to break the dependence. This version of
// the tool instead will generate interfaces for all of the required types.
//
// This means that developers will only ever need to interact with these
// interfaces, and could switch out using this implementation for another one of
// their own choosing.
//
// Also note that the manager links against all the implementations to generate
// a comprehensive registry. So while individual properties and types are able
// to be compiled separately, this generated output will link against all of
// these libraries.
//
// TODO: Improve the code generation to examine specific Golang code to
// determine which types to actually generate, and prune the unneeded types.
// This would cut down on the bloat on a per-program basis.
type ManagerGenerator struct {
pm PackageManager
tg []*TypeGenerator
fp []*FunctionalPropertyGenerator
nfp []*NonFunctionalPropertyGenerator
// Constructed at creation time. These rely on pointer stability,
// which should happen as none of these generators are treated as
// values.
tgManagedMethods map[*TypeGenerator]*managedMethods
fpManagedMethods map[*FunctionalPropertyGenerator]*managedMethods
nfpManagedMethods map[*NonFunctionalPropertyGenerator]*managedMethods
// Cached during manager code generation.
cacheOnce sync.Once
cachedStruct *codegen.Struct
}
// managedMethods caches the specific methods and interfaces mapped to specific
// properties and types.
type managedMethods struct {
deserializor *codegen.Method
publicDeserializor *codegen.Method
// Interface for a manager
mIface *codegen.Interface
// Interface(s) for the property/type
ifaces []*codegen.Interface
}
// NewManagerGenerator creates a new manager system.
//
// This generator should be constructed in the third pass, after types and
// property generators are all constructed.
func NewManagerGenerator(pm PackageManager,
tg []*TypeGenerator,
fp []*FunctionalPropertyGenerator,
nfp []*NonFunctionalPropertyGenerator) (*ManagerGenerator, error) {
mg := &ManagerGenerator{
pm: pm,
tg: tg,
fp: fp,
nfp: nfp,
tgManagedMethods: make(map[*TypeGenerator]*managedMethods, len(tg)),
fpManagedMethods: make(map[*FunctionalPropertyGenerator]*managedMethods, len(fp)),
nfpManagedMethods: make(map[*NonFunctionalPropertyGenerator]*managedMethods, len(nfp)),
}
// Pass 1: Get all deserializor-like methods created. Further passes may
// rely on already having this data available in the manager.
for _, t := range tg {
mg.tgManagedMethods[t] = &managedMethods{
// TODO: Figure out how to use this instead of the Kind abstraction
deserializor: mg.createPrivateDeserializationMethodForType(t),
publicDeserializor: nil,
mIface: nil,
}
}
for _, p := range fp {
mg.fpManagedMethods[p] = &managedMethods{
deserializor: mg.createPrivateDeserializationMethodForFuncProperty(p),
publicDeserializor: nil,
mIface: nil,
}
}
for _, p := range nfp {
mg.nfpManagedMethods[p] = &managedMethods{
deserializor: mg.createPrivateDeserializationMethodForNonFuncProperty(p),
publicDeserializor: nil,
mIface: nil,
}
}
// Pass 2: Inform the type of this ManagerGenerator so that it can keep
// all of its bookkeeping straight.
for _, t := range tg {
if e := t.apply(mg); e != nil {
return nil, e
}
}
// Pass 3: Populate interfaces of the types and properties, which relies
// on the first pass's data population.
for _, t := range tg {
publicPkg := t.Package().Parent().PublicPackage()
mg.tgManagedMethods[t].ifaces = []*codegen.Interface{t.toInterface(publicPkg)}
}
// TODO: Move these back to pass 1
for _, p := range fp {
publicPkg := p.GetPackage().Parent().PublicPackage()
mg.fpManagedMethods[p].ifaces = []*codegen.Interface{p.toInterface(publicPkg)}
}
for _, p := range nfp {
publicPkg := p.GetPackage().Parent().PublicPackage()
mg.nfpManagedMethods[p].ifaces = p.toInterfaces(publicPkg)
}
return mg, nil
}
func (m *ManagerGenerator) publicManager() *codegen.Struct {
// TODO
return nil
}
func (m *ManagerGenerator) privatePackage() Package {
return m.pm.PrivatePackage()
}
func (m *ManagerGenerator) getPrivateDeserializationMethodForType(t *TypeGenerator) *codegen.Method {
return m.tgManagedMethods[t].deserializor
}
func (m *ManagerGenerator) getPrivateDeserializationMethodForProperty(p Property) *codegen.Method {
switch v := p.(type) {
case *FunctionalPropertyGenerator:
return m.fpManagedMethods[v].deserializor
case *NonFunctionalPropertyGenerator:
return m.nfpManagedMethods[v].deserializor
default:
panic("unknown property type")
}
}
// PrivateManager creates a manager implementation that works with the concrete
// types required by the other PropertyGenerators and TypeGenerators for
// serializing and deserializing.
//
// Applications should NOT use this private manager as it will force them to
// rely on the concrete type implementations. The public version uses interfaces
// which isolates Application code from this specific go-fed implementation. If
// another alternative to go-fed were to be created, it could target those
// interfaces and be a drop-in replacement for everyone's applications.
//
// It is necessary to acheive isolation without cyclic dependencies: types and
// properties can each belong in their own package (if desired) to minimize
// binary bloat. This is theoretical until the below TODO is tackled because
// this concrete implementation relies on linking against all of the types and
// properties to behave correctly. There is no simple way around this. But I am
// preparing for the better solution here.
//
// TODO: Analyze a given program, and only generate the types and properties in
// use by the go program.
func (m *ManagerGenerator) PrivateManager() *codegen.Struct {
var methods []*codegen.Method
// TODO: Interface versions of these methods should also be present for
// these specific types.
for _, tg := range m.tgManagedMethods {
methods = append(methods, tg.deserializor)
}
for _, fp := range m.fpManagedMethods {
methods = append(methods, fp.deserializor)
}
for _, nfp := range m.nfpManagedMethods {
methods = append(methods, nfp.deserializor)
}
var functions []*codegen.Function
var members []jen.Code
s := codegen.NewStruct(
jen.Commentf(fmt.Sprintf("%s privately manages concrete types and deserializations for internal use by generated code. Application code should use the public version instead, which uses interfaces to abstract away the generated code and allow apps to not entirely rely on go-fed should they choose not to.", managerName)),
managerName,
methods,
functions,
members)
return s
}
// createPrivateDeserializationMethodForType creates a new method for the
// private manager.
//
// TODO: Unify these three methods behind some kind of interface.
func (m *ManagerGenerator) createPrivateDeserializationMethodForType(tg *TypeGenerator) *codegen.Method {
dn := tg.deserializationFnName()
pkg := m.pm.PrivatePackage()
name := fmt.Sprintf("%s%s%s", dn, tg.Package().Name(), strings.Title(pkg.Name()))
return codegen.NewCommentedValueMethod(
pkg.Path(),
name,
managerName,
/*param=*/ nil,
[]jen.Code{
jen.Func().Params(
jen.Map(jen.String()).Interface(),
).Params(
// TODO: Qualify this.
jen.Op("*").Id(tg.TypeName()),
jen.Error(),
),
},
[]jen.Code{
jen.Return(
jen.Qual(tg.Package().Path(), dn),
),
},
jen.Commentf("%s returns the deserialization method for the %q type in package %q", name, tg.TypeName(), tg.Package().Name()))
}
// createPrivateDeserializationMethodForFuncProperty creates a new method for the
// private manager.
//
// TODO: Unify these three methods behind some kind of interface.
func (m *ManagerGenerator) createPrivateDeserializationMethodForFuncProperty(fp *FunctionalPropertyGenerator) *codegen.Method {
dn := fp.DeserializeFnName()
pkg := m.pm.PrivatePackage()
name := fmt.Sprintf("%s%s%s", dn, fp.Package.Name(), strings.Title(pkg.Name()))
return codegen.NewCommentedValueMethod(
pkg.Path(),
name,
managerName,
/*param=*/ nil,
[]jen.Code{
jen.Func().Params(
jen.Map(jen.String()).Interface(),
).Params(
// TODO: Qualify this.
jen.Op("*").Id(fp.StructName()),
jen.Error(),
),
},
[]jen.Code{
jen.Return(
jen.Qual(fp.Package.Path(), dn),
),
},
jen.Commentf("%s returns the deserialization method for the %q functional property in package %q", name, fp.StructName(), fp.Package.Name()))
}
// createPrivateDeserializationMethodForNonFuncProperty creates a new method for the
// private manager.
//
// TODO: Unify these three methods behind some kind of interface.
func (m *ManagerGenerator) createPrivateDeserializationMethodForNonFuncProperty(nfp *NonFunctionalPropertyGenerator) *codegen.Method {
dn := nfp.DeserializeFnName()
pkg := m.pm.PrivatePackage()
name := fmt.Sprintf("%s%s%s", dn, nfp.Package.Name(), strings.Title(pkg.Name()))
return codegen.NewCommentedValueMethod(
pkg.Path(),
name,
managerName,
/*param=*/ nil,
[]jen.Code{
jen.Func().Params(
jen.Map(jen.String()).Interface(),
).Params(
// TODO: Qualify this.
jen.Op("*").Id(nfp.StructName()),
jen.Error(),
),
},
[]jen.Code{
jen.Return(
jen.Qual(nfp.Package.Path(), dn),
),
},
jen.Commentf("%s returns the deserialization method for the %q non-functional property in package %q", name, nfp.StructName(), nfp.Package.Name()))
}

ファイルの表示

@ -20,7 +20,10 @@ type NonFunctionalPropertyGenerator struct {
// NewNonFunctionalPropertyGenerator is a convenience constructor to create
// NonFunctionalPropertyGenerators.
func NewNonFunctionalPropertyGenerator(pkg string,
//
// PropertyGenerators shoulf be in the first pass to construct, before types and
// other generators are constructed.
func NewNonFunctionalPropertyGenerator(pkg Package,
name Identifier,
kinds []Kind,
hasNaturalLanguageMap bool) *NonFunctionalPropertyGenerator {
@ -34,12 +37,25 @@ func NewNonFunctionalPropertyGenerator(pkg string,
}
}
// toInterfaces creates the interface versions of the definitions generated.
func (p *NonFunctionalPropertyGenerator) toInterfaces(pkg Package) []*codegen.Interface {
s, t := p.Definitions()
return []*codegen.Interface{
s.ToInterface(pkg.Path(), p.InterfaceName(), ""),
t.ToInterface(pkg.Path(), p.elementTypeGenerator().InterfaceName(), ""),
}
}
// Definitions produces the Go code definitions, which can generate their Go
// implementations. The struct is the iterator for various values of the
// property, which is defined by the type definition.
func (p *NonFunctionalPropertyGenerator) Definitions() (*codegen.Struct, *codegen.Typedef) {
p.cacheOnce.Do(func() {
methods, funcs := p.serializationFuncs()
var methods []*codegen.Method
var funcs []*codegen.Function
ser, deser := p.serializationFuncs()
methods = append(methods, ser)
funcs = append(funcs, deser)
methods = append(methods, p.funcs()...)
property := codegen.NewTypedef(
jen.Commentf("%s is the non-functional property %q. It is permitted to have one or more values, and of different value types.", p.StructName(), p.PropertyName()),
@ -90,7 +106,7 @@ func (p *NonFunctionalPropertyGenerator) funcs() []*codegen.Method {
prependMethodName := fmt.Sprintf("%s%s", prependMethod, p.kindCamelName(i))
methods = append(methods,
codegen.NewCommentedPointerMethod(
p.PackageName(),
p.Package.Path(),
prependMethodName,
p.StructName(),
[]jen.Code{jen.Id("v").Id(kind.ConcreteKind)},
@ -108,7 +124,7 @@ func (p *NonFunctionalPropertyGenerator) funcs() []*codegen.Method {
appendMethodName := fmt.Sprintf("%s%s", appendMethod, p.kindCamelName(i))
methods = append(methods,
codegen.NewCommentedPointerMethod(
p.PackageName(),
p.Package.Path(),
appendMethodName,
p.StructName(),
[]jen.Code{jen.Id("v").Id(kind.ConcreteKind)},
@ -140,7 +156,7 @@ func (p *NonFunctionalPropertyGenerator) funcs() []*codegen.Method {
// Remove Method
methods = append(methods,
codegen.NewCommentedPointerMethod(
p.PackageName(),
p.Package.Path(),
removeMethod,
p.StructName(),
[]jen.Code{jen.Id("idx").Int()},
@ -176,7 +192,7 @@ func (p *NonFunctionalPropertyGenerator) funcs() []*codegen.Method {
// Len Method
methods = append(methods,
codegen.NewCommentedValueMethod(
p.PackageName(),
p.Package.Path(),
lenMethod,
p.StructName(),
/*params=*/ nil,
@ -192,7 +208,7 @@ func (p *NonFunctionalPropertyGenerator) funcs() []*codegen.Method {
// Swap Method
methods = append(methods,
codegen.NewCommentedValueMethod(
p.PackageName(),
p.Package.Path(),
swapMethod,
p.StructName(),
[]jen.Code{
@ -213,7 +229,7 @@ func (p *NonFunctionalPropertyGenerator) funcs() []*codegen.Method {
// Less Method
methods = append(methods,
codegen.NewCommentedValueMethod(
p.PackageName(),
p.Package.Path(),
lessMethod,
p.StructName(),
[]jen.Code{
@ -235,7 +251,7 @@ func (p *NonFunctionalPropertyGenerator) funcs() []*codegen.Method {
// Kind Method
methods = append(methods,
codegen.NewCommentedValueMethod(
p.PackageName(),
p.Package.Path(),
kindIndexMethod,
p.StructName(),
[]jen.Code{jen.Id("idx").Int()},
@ -252,52 +268,49 @@ func (p *NonFunctionalPropertyGenerator) funcs() []*codegen.Method {
// serializationFuncs produces the Methods and Functions needed for a
// NonFunctional property to be serialized and deserialized to and from an
// encoding.
func (p *NonFunctionalPropertyGenerator) serializationFuncs() ([]*codegen.Method, []*codegen.Function) {
serialize := []*codegen.Method{
codegen.NewCommentedValueMethod(
p.PackageName(),
p.serializeFnName(),
p.StructName(),
/*params=*/ nil,
[]jen.Code{jen.Interface(), jen.Error()},
[]jen.Code{
jen.Id("s").Op(":=").Make(
jen.Index().Interface(),
jen.Lit(0),
jen.Len(jen.Id(codegen.This())),
),
jen.For(
func (p *NonFunctionalPropertyGenerator) serializationFuncs() (*codegen.Method, *codegen.Function) {
serialize := codegen.NewCommentedValueMethod(
p.Package.Path(),
p.serializeFnName(),
p.StructName(),
/*params=*/ nil,
[]jen.Code{jen.Interface(), jen.Error()},
[]jen.Code{
jen.Id("s").Op(":=").Make(
jen.Index().Interface(),
jen.Lit(0),
jen.Len(jen.Id(codegen.This())),
),
jen.For(
jen.List(
jen.Id("_"),
jen.Id("iterator"),
).Op(":=").Range().Id(codegen.This()),
).Block(
jen.If(
jen.List(
jen.Id("_"),
jen.Id("iterator"),
).Op(":=").Range().Id(codegen.This()),
jen.Id("b"),
jen.Err(),
).Op(":=").Id("iterator").Dot(serializeIteratorMethod).Call(),
jen.Err().Op("!=").Nil(),
).Block(
jen.If(
jen.List(
jen.Id("b"),
jen.Err(),
).Op(":=").Id("iterator").Dot(serializeIteratorMethod).Call(),
jen.Err().Op("!=").Nil(),
).Block(
jen.Return(
jen.Id("s"),
jen.Err(),
),
).Else().Block(
jen.Id("s").Op("=").Append(
jen.Id("s"),
jen.Id("b"),
),
jen.Return(
jen.Id("s"),
jen.Err(),
),
).Else().Block(
jen.Id("s").Op("=").Append(
jen.Id("s"),
jen.Id("b"),
),
),
jen.Return(
jen.Id("s"),
jen.Nil(),
),
},
jen.Commentf("%s converts this into an interface representation suitable for marshalling into a text or binary format.", p.serializeFnName()),
),
}
),
jen.Return(
jen.Id("s"),
jen.Nil(),
),
},
jen.Commentf("%s converts this into an interface representation suitable for marshalling into a text or binary format.", p.serializeFnName()))
deserializeFn := func(variable string) jen.Code {
return jen.If(
jen.List(
@ -321,51 +334,48 @@ func (p *NonFunctionalPropertyGenerator) serializationFuncs() ([]*codegen.Method
),
)
}
deserialize := []*codegen.Function{
codegen.NewCommentedFunction(
p.PackageName(),
p.DeserializeFnName(),
[]jen.Code{jen.Id("m").Map(jen.String()).Interface()},
[]jen.Code{jen.Id(p.StructName()), jen.Error()},
[]jen.Code{
jen.Var().Id(codegen.This()).Index().Id(p.iteratorTypeName().CamelName),
deserialize := codegen.NewCommentedFunction(
p.Package.Path(),
p.DeserializeFnName(),
[]jen.Code{jen.Id("m").Map(jen.String()).Interface()},
[]jen.Code{jen.Id(p.StructName()), jen.Error()},
[]jen.Code{
jen.Var().Id(codegen.This()).Index().Id(p.iteratorTypeName().CamelName),
jen.If(
jen.List(
jen.Id("i"),
jen.Id("ok"),
).Op(":=").Id("m").Index(
jen.Lit(p.PropertyName()),
),
jen.Id("ok"),
).Block(
jen.If(
jen.List(
jen.Id("i"),
jen.Id("list"),
jen.Id("ok"),
).Op(":=").Id("m").Index(
jen.Lit(p.PropertyName()),
).Op(":=").Id("i").Assert(
jen.Index().Interface(),
),
jen.Id("ok"),
).Block(
jen.If(
jen.For(
jen.List(
jen.Id("list"),
jen.Id("ok"),
).Op(":=").Id("i").Assert(
jen.Index().Interface(),
),
jen.Id("ok"),
jen.Id("_"),
jen.Id("iterator"),
).Op(":=").Range().Id("list"),
).Block(
jen.For(
jen.List(
jen.Id("_"),
jen.Id("iterator"),
).Op(":=").Range().Id("list"),
).Block(
deserializeFn("iterator"),
),
).Else().Block(
deserializeFn("i"),
deserializeFn("iterator"),
),
).Else().Block(
deserializeFn("i"),
),
jen.Return(
jen.Id(codegen.This()),
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.Return(
jen.Id(codegen.This()),
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()))
return serialize, deserialize
}

79
tools/exp/props/pkg.go ノーマルファイル
ファイルの表示

@ -0,0 +1,79 @@
package props
import (
"fmt"
"strings"
)
// PackageManager manages the path and names of a package consisting of a public
// and a private portion.
type PackageManager struct {
root string
public string
private string
}
func NewPackageManager(root string) *PackageManager {
return &PackageManager{
root: root,
public: "",
private: "internal",
}
}
// PublicPackage returns the public package.
func (p *PackageManager) PublicPackage() Package {
return p.toPackage(p.public, true)
}
// PrivatePackage returns the private package.
func (p *PackageManager) PrivatePackage() Package {
return p.toPackage(p.private, false)
}
// Sub creates a PackageManager clone that manages a subdirectory.
func (p *PackageManager) Sub(name string) *PackageManager {
return &PackageManager{
root: fmt.Sprintf("%s/%s", p.root, name),
public: p.public,
private: p.private,
}
}
func (p *PackageManager) toPackage(suffix string, public bool) Package {
path := p.root
if len(suffix) > 0 {
path = strings.Join([]string{p.root, suffix}, "/")
}
s := strings.Split(path, "/")
name := s[len(s)-1]
return Package{
path: path,
name: name,
isPublic: public,
parent: p,
}
}
type Package struct {
path string
name string
isPublic bool
parent *PackageManager
}
func (p Package) Path() string {
return p.path
}
func (p Package) Name() string {
return p.name
}
func (p Package) IsPublic() bool {
return p.isPublic
}
func (p Package) Parent() *PackageManager {
return p.parent
}

ファイルの表示

@ -59,12 +59,13 @@ type Identifier struct {
// deserialize such types, compare the types, and other meta-information to use
// during Go code generation.
type Kind struct {
Name Identifier
ConcreteKind string
Nilable bool
SerializeFn *codegen.Function
DeserializeFn *codegen.Function
LessFn *codegen.Function
Name Identifier
ConcreteKind string
Nilable bool
// Expected to be a jen.Qual
SerializeFn *jen.Statement
DeserializeFn *jen.Statement
LessFn *jen.Statement
}
// PropertyGenerator is a common base struct used in both Functional and
@ -77,15 +78,15 @@ type Kind struct {
// TODO: Make this type private
type PropertyGenerator struct {
// TODO: Make these private
Package string
Package Package
Name Identifier
Kinds []Kind
HasNaturalLanguageMap bool
asIterator bool
}
// PackageName returns the name of the package for the property to be generated.
func (p *PropertyGenerator) PackageName() string {
// GetPackage gets this property's Package.
func (p *PropertyGenerator) GetPackage() Package {
return p.Package
}
@ -95,7 +96,7 @@ func (p *PropertyGenerator) PackageName() string {
// 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 {
func (p *PropertyGenerator) SetKindFns(name string, ser, deser, less *jen.Statement) error {
for i, kind := range p.Kinds {
if kind.Name.LowerName == name {
if kind.SerializeFn != nil || kind.DeserializeFn != nil || kind.LessFn != nil {
@ -120,6 +121,11 @@ func (p *PropertyGenerator) StructName() string {
return fmt.Sprintf("%sProperty", p.Name.CamelName)
}
// InterfaceNAme returns the interface name of the property type.
func (p *PropertyGenerator) InterfaceName() string {
return fmt.Sprintf("%sInterface", p.StructName())
}
// PropertyName returns the name of this property, as defined in
// specifications. It is not suitable for use in generated code function
// identifiers.
@ -201,7 +207,7 @@ func (p *PropertyGenerator) clearMethodName() string {
func (p *PropertyGenerator) commonMethods() []*codegen.Method {
return []*codegen.Method{
codegen.NewCommentedValueMethod(
p.PackageName(),
p.Package.Path(),
nameMethod,
p.StructName(),
/*params=*/ nil,

ファイルの表示

@ -27,7 +27,7 @@ const (
// TypeInterface returns the Type Interface that is needed for ActivityStream
// types to compile for methods dealing with extending, in the inheritance
// sense.
func TypeInterface(pkg string) *codegen.Interface {
func TypeInterface(pkg Package) *codegen.Interface {
comment := fmt.Sprintf("%s represents an ActivityStreams type.", typeInterfaceName)
funcs := []codegen.FunctionSignature{
{
@ -37,28 +37,30 @@ func TypeInterface(pkg string) *codegen.Interface {
Comment: fmt.Sprintf("%s returns the ActivityStreams type name.", typeNameMethod),
},
}
return codegen.NewInterface(pkg, typeInterfaceName, funcs, comment)
return codegen.NewInterface(pkg.Path(), typeInterfaceName, funcs, comment)
}
// Property represents a property of an ActivityStreams type.
type Property interface {
PackageName() string
GetPackage() Package
PropertyName() string
StructName() string
SetKindFns(name string, ser, deser, less *codegen.Function) error
SetKindFns(name string, ser, deser, less *jen.Statement) error
DeserializeFnName() string
}
// TypeGenerator represents an ActivityStream type definition to generate in Go.
type TypeGenerator struct {
packageName string
pkg Package
typeName string
comment string
properties map[string]Property
withoutProperties map[string]Property
rangeProperties []Property
extends []*TypeGenerator
disjoint []*TypeGenerator
extendedBy []*TypeGenerator
m *ManagerGenerator
cacheOnce sync.Once
cachedStruct *codegen.Struct
}
@ -67,23 +69,32 @@ type TypeGenerator struct {
// or extension type. It will return an error if there are multiple properties
// have the same Name.
//
// The TypeGenerator should be in the second pass to construct, relying on the
// fact that properties have already been constructed.
//
// The extends and disjoint parameters are allowed to be nil. These lists must
// also have unique (non-duplicated) elements.
// also have unique (non-duplicated) elements. Note that the disjoint entries
// will be set up bi-directionally properly; no need to go back to an existing
// TypeGenerator to set up the link correctly.
//
// The rangeProperties list is allowed to be nil. Any passed in will properly
// have their SetKindFns bookkeeping done.
//
// All TypeGenerators must be created before the Definition method is called, to
// ensure that type extension, in the inheritence sense, is properly set up.
// Additionally, all properties whose range is this type should have their
// SetKindFns method called with this TypeGenerator's KindSerializationFuncs for
// all code generation to correctly reference each other.
func NewTypeGenerator(packageName, typeName, comment string,
properties, withoutProperties []Property,
//
// A ManagerGenerator must be created with this type before Definition is
// called, to ensure that the serialization functions are properly set up.
func NewTypeGenerator(pkg Package, typeName, comment string,
properties, withoutProperties, rangeProperties []Property,
extends, disjoint []*TypeGenerator) (*TypeGenerator, error) {
t := &TypeGenerator{
packageName: packageName,
pkg: pkg,
typeName: typeName,
comment: comment,
properties: make(map[string]Property, len(properties)),
withoutProperties: make(map[string]Property, len(withoutProperties)),
rangeProperties: rangeProperties,
extends: extends,
disjoint: disjoint,
}
@ -103,12 +114,34 @@ func NewTypeGenerator(packageName, typeName, comment string,
for _, ext := range extends {
ext.extendedBy = append(ext.extendedBy, t)
}
// Complete doubly-linked disjoint types.
for _, disj := range disjoint {
disj.disjoint = append(disj.disjoint, t)
}
return t, nil
}
// AddDisjoint adds another TypeGenerator that is disjoint to this one.
func (t *TypeGenerator) AddDisjoint(o *TypeGenerator) {
t.disjoint = append(t.disjoint, o)
// apply propagates the manager's functions referring to this type's
// implementation as if this type were a Kind.
//
// Prepares to use the manager for the Definition generation.
func (t *TypeGenerator) apply(m *ManagerGenerator) error {
t.m = m
// Set up Kind functions
ser := jen.Qual(t.Package().Path(), t.serializationFnName())
deser := jen.Qual(m.privatePackage().Path(), m.getPrivateDeserializationMethodForType(t).Name())
less := jen.Qual(t.Package().Path(), t.lessFnName())
for _, p := range t.rangeProperties {
if e := p.SetKindFns(t.TypeName(), ser, deser, less); e != nil {
return e
}
}
return nil
}
// Package gets this TypeGenerator's Package.
func (t *TypeGenerator) Package() Package {
return t.pkg
}
// Comment returns the comment for this type.
@ -121,6 +154,11 @@ func (t *TypeGenerator) TypeName() string {
return t.typeName
}
// InterfaceName returns the interface name for this type.
func (t *TypeGenerator) InterfaceName() string {
return fmt.Sprintf("%sInterface", t.TypeName())
}
// Extends returns the generators of types that this ActivityStreams type
// extends from.
func (t *TypeGenerator) Extends() []*TypeGenerator {
@ -169,12 +207,37 @@ func (t *TypeGenerator) disjointWithFnName() string {
return fmt.Sprintf("%s%s", t.TypeName(), disjointWithMethod)
}
// deserializationFnName determines the name of the deserialize function for
// this type.
func (t *TypeGenerator) deserializationFnName() string {
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.
//
// Requires apply to have already been called.
func (t *TypeGenerator) toInterface(pkg Package) *codegen.Interface {
s := t.Definition()
return s.ToInterface(pkg.Path(), t.InterfaceName(), "")
}
// Definition generates the golang code for this ActivityStreams type.
func (t *TypeGenerator) Definition() *codegen.Struct {
t.cacheOnce.Do(func() {
members := t.members()
m := t.serializationMethod()
ser, deser, less := t.KindSerializationFuncs()
ser, deser, less := t.kindSerializationFuncs()
extendsFn, extendsMethod := t.extendsDefinition()
t.cachedStruct = codegen.NewStruct(
jen.Commentf(t.Comment()),
@ -241,7 +304,7 @@ func (t *TypeGenerator) members() (members []jen.Code) {
// Convert to jen.Code
members = make([]jen.Code, 0, len(p))
for _, property := range sortedMembers {
members = append(members, jen.Id(strings.Title(property.PropertyName())).Qual(property.PackageName(), property.StructName()))
members = append(members, jen.Id(strings.Title(property.PropertyName())).Qual(property.GetPackage().Path(), property.StructName()))
}
return
}
@ -250,7 +313,7 @@ func (t *TypeGenerator) members() (members []jen.Code) {
// type name.
func (t *TypeGenerator) nameDefinition() *codegen.Method {
return codegen.NewCommentedValueMethod(
t.packageName,
t.pkg.Path(),
typeNameMethod,
t.TypeName(),
/*params=*/ nil,
@ -300,14 +363,14 @@ func (t *TypeGenerator) extendsDefinition() (*codegen.Function, *codegen.Method)
jen.Return(jen.False())}
}
f := codegen.NewCommentedFunction(
t.packageName,
t.pkg.Path(),
t.extendsFnName(),
[]jen.Code{jen.Id("other").Id(typeInterfaceName)},
[]jen.Code{jen.Bool()},
impl,
jen.Commentf("%s returns true if the %s type extends from the other type.", t.extendsFnName(), t.TypeName()))
m := codegen.NewCommentedValueMethod(
t.packageName,
t.pkg.Path(),
extendingMethod,
t.TypeName(),
[]jen.Code{jen.Id("other").Id(typeInterfaceName)},
@ -356,7 +419,7 @@ func (t *TypeGenerator) extendedByDefinition() *codegen.Function {
jen.Return(jen.False())}
}
return codegen.NewCommentedFunction(
t.packageName,
t.pkg.Path(),
t.extendedByFnName(),
[]jen.Code{jen.Id("other").Id(typeInterfaceName)},
[]jen.Code{jen.Bool()},
@ -402,7 +465,7 @@ func (t *TypeGenerator) disjointWithDefinition() *codegen.Function {
jen.Return(jen.False())}
}
return codegen.NewCommentedFunction(
t.packageName,
t.pkg.Path(),
t.disjointWithFnName(),
[]jen.Code{jen.Id("other").Id(typeInterfaceName)},
[]jen.Code{jen.Bool()},
@ -414,7 +477,7 @@ func (t *TypeGenerator) disjointWithDefinition() *codegen.Function {
// a property.
func (t *TypeGenerator) serializationMethod() (ser *codegen.Method) {
ser = codegen.NewCommentedValueMethod(
t.packageName,
t.pkg.Path(),
serializeMethodName,
t.TypeName(),
/*params=*/ nil,
@ -427,13 +490,12 @@ func (t *TypeGenerator) serializationMethod() (ser *codegen.Method) {
return
}
// KindSerializationFuncs returns free function references that can be used to
// 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())
func (t *TypeGenerator) kindSerializationFuncs() (ser, deser, less *codegen.Function) {
ser = codegen.NewCommentedFunction(
t.packageName,
serName,
t.pkg.Path(),
t.serializationFnName(),
[]jen.Code{jen.Id("s").Id(t.TypeName())},
[]jen.Code{jen.Interface(), jen.Error()},
[]jen.Code{
@ -441,16 +503,16 @@ func (t *TypeGenerator) KindSerializationFuncs() (ser, deser, less *codegen.Func
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())
jen.Commentf("%s calls %s on the %s type.", t.serializationFnName(), serializeMethodName, t.TypeName()))
deserCode := jen.Empty()
for name, prop := range t.allProperties() {
deserMethod := t.m.getPrivateDeserializationMethodForProperty(prop)
deserCode = deserCode.Add(
jen.If(
jen.List(
jen.Id("p"),
jen.Err(),
).Op(":=").Qual(prop.PackageName(), prop.DeserializeFnName()).Call(jen.Id("m")),
).Op(":=").Add(deserMethod.Call(managerInitName())).Call(jen.Id("m")),
jen.Err().Op("!=").Nil(),
).Block(
jen.Return(jen.Nil(), jen.Err()),
@ -459,8 +521,8 @@ func (t *TypeGenerator) KindSerializationFuncs() (ser, deser, less *codegen.Func
).Line())
}
deser = codegen.NewCommentedFunction(
t.packageName,
deserName,
t.pkg.Path(),
t.deserializationFnName(),
[]jen.Code{jen.Id("m").Map(jen.String()).Interface()},
[]jen.Code{jen.Op("*").Id(t.TypeName()), jen.Error()},
[]jen.Code{
@ -468,11 +530,10 @@ func (t *TypeGenerator) KindSerializationFuncs() (ser, deser, less *codegen.Func
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())
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.packageName,
lessName,
t.pkg.Path(),
t.lessFnName(),
[]jen.Code{
jen.Id("i"),
jen.Id("j").Op("*").Id(t.TypeName()),
@ -482,6 +543,6 @@ func (t *TypeGenerator) KindSerializationFuncs() (ser, deser, less *codegen.Func
// 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()))
jen.Commentf("%s computes which %s is lesser, with an arbitrary but stable determination", t.lessFnName(), t.TypeName()))
return
}

ファイルの表示

@ -153,6 +153,10 @@ func (v VocabularyType) GetName() string {
return v.Name
}
func (v VocabularyType) TypeName() string {
return v.Name
}
func (v *VocabularyType) SetURI(s string) error {
var e error
v.URI, e = url.Parse(s)
@ -203,6 +207,10 @@ func (v VocabularyProperty) GetName() string {
return v.Name
}
func (v VocabularyProperty) PropertyName() string {
return v.Name
}
func (v *VocabularyProperty) SetURI(s string) error {
var e error
v.URI, e = url.Parse(s)