Fix init generation for multiple vocabularies.

このコミットが含まれているのは:
Cory Slep 2019-01-18 21:22:07 +01:00
コミット c3b9686d1f
2個のファイルの変更115行の追加46行の削除

ファイルの表示

@ -44,6 +44,49 @@ func newVocabulary() vocabulary {
}
}
// allTypeArray converts all Types, including referenced Types, to an array.
func (v vocabulary) allTypeArray() []*gen.TypeGenerator {
var typeArray []*gen.TypeGenerator
for _, ref := range v.References {
typeArray = append(typeArray, ref.typeArray()...)
}
typeArray = append(typeArray, v.typeArray()...)
return typeArray
}
// allPropArray converts all Properties, including referenced Properties, to an
// array.
func (v vocabulary) allPropArray() []*gen.PropertyGenerator {
var propArray []*gen.PropertyGenerator
for _, ref := range v.References {
propArray = append(propArray, ref.propArray()...)
}
propArray = append(propArray, v.propArray()...)
return propArray
}
// allFuncPropArray converts all FProps, including referenced Properties, to an
// array.
func (v vocabulary) allFuncPropArray() []*gen.FunctionalPropertyGenerator {
var funcPropArray []*gen.FunctionalPropertyGenerator
for _, ref := range v.References {
funcPropArray = append(funcPropArray, ref.funcPropArray()...)
}
funcPropArray = append(funcPropArray, v.funcPropArray()...)
return funcPropArray
}
// allNonFuncPropArray converts all NFProps, including referenced Properties, to
// an array.
func (v vocabulary) allNonFuncPropArray() []*gen.NonFunctionalPropertyGenerator {
var nonFuncPropArray []*gen.NonFunctionalPropertyGenerator
for _, ref := range v.References {
nonFuncPropArray = append(nonFuncPropArray, ref.nonFuncPropArray()...)
}
nonFuncPropArray = append(nonFuncPropArray, v.nonFuncPropArray()...)
return nonFuncPropArray
}
// typeArray converts Types to an array.
func (v vocabulary) typeArray() []*gen.TypeGenerator {
tg := make([]*gen.TypeGenerator, 0, len(v.Types))
@ -202,11 +245,8 @@ func (c Converter) Convert(p *rdf.ParsedVocabulary) (f []*File, e error) {
// convertToFiles takes the generators for a vocabulary and maps them into a
// file structure.
func (c Converter) convertToFiles(v vocabulary) (f []*File, e error) {
// Values -- include all referenced values too.
for _, v := range v.Values {
pkg := c.valuePackage(v)
f = append(f, convertValue(pkg, v))
}
pub := c.GenRoot.PublicPackage()
// References
for _, ref := range v.References {
for _, v := range ref.Values {
pkg := c.valuePackage(v)
@ -218,6 +258,22 @@ func (c Converter) convertToFiles(v vocabulary) (f []*File, e error) {
return
}
f = append(f, files...)
files, e = c.rootFiles(pub, ref.Name, *ref, v.Manager)
if e != nil {
return
}
f = append(f, files...)
pkgFiles, err := c.packageFiles(*ref)
if err != nil {
e = err
return
}
f = append(f, pkgFiles...)
}
// This vocabulary
for _, v := range v.Values {
pkg := c.valuePackage(v)
f = append(f, convertValue(pkg, v))
}
var files []*File
files, e = c.toFiles(v)
@ -225,26 +281,32 @@ func (c Converter) convertToFiles(v vocabulary) (f []*File, e error) {
return
}
f = append(f, files...)
files, e = c.rootFiles(pub, v.Name, v, v.Manager)
if e != nil {
return
}
f = append(f, files...)
pkgFiles, err := c.packageFiles(v)
if err != nil {
e = err
return
}
f = append(f, pkgFiles...)
// Manager
pub := c.GenRoot.PublicPackage()
file := jen.NewFilePath(pub.Path())
file.Add(v.Manager.Definition().Definition())
f = append(f, &File{
F: file,
FileName: "gen_manager.go",
Directory: pub.WriteDir(),
})
files, e = c.rootFiles(pub, v.Name, v)
// Init file
var file *File
file, e = c.initFile(pub, v)
if e != nil {
return
}
f = append(f, files...)
f = append(f, file)
// Manager
jenFile := jen.NewFilePath(pub.Path())
jenFile.Add(v.Manager.Definition().Definition())
f = append(f, &File{
F: jenFile,
FileName: "gen_manager.go",
Directory: pub.WriteDir(),
})
// Root Package Documentation
rootDocFile := jen.NewFilePath(pub.Path())
rootDocFile.PackageComment(gen.GenRootPackageComment(pub.Name()))
@ -319,22 +381,11 @@ func (c Converter) convertVocabulary(p *rdf.ParsedVocabulary, refs map[string]*v
// convertGenRoot creates code-wide code generators.
func (c Converter) convertGenRoot(v *vocabulary) (e error) {
var typeArray []*gen.TypeGenerator
var funcPropArray []*gen.FunctionalPropertyGenerator
var nonFuncPropArray []*gen.NonFunctionalPropertyGenerator
for _, ref := range v.References {
typeArray = append(typeArray, ref.typeArray()...)
funcPropArray = append(funcPropArray, ref.funcPropArray()...)
nonFuncPropArray = append(nonFuncPropArray, ref.nonFuncPropArray()...)
}
typeArray = append(typeArray, v.typeArray()...)
funcPropArray = append(funcPropArray, v.funcPropArray()...)
nonFuncPropArray = append(nonFuncPropArray, v.nonFuncPropArray()...)
v.Manager, e = gen.NewManagerGenerator(
c.GenRoot.PublicPackage(),
typeArray,
funcPropArray,
nonFuncPropArray)
v.allTypeArray(),
v.allFuncPropArray(),
v.allNonFuncPropArray())
return
}
@ -762,16 +813,9 @@ func (c Converter) packageManager(s, vocabName string) (pkg *gen.PackageManager,
// rootFiles creates files that are applied for all vocabularies. These files
// are the ones typically used by developers.
func (c Converter) rootFiles(pkg gen.Package, vocabName string, v vocabulary) (f []*File, e error) {
func (c Converter) rootFiles(pkg gen.Package, vocabName string, v vocabulary, m *gen.ManagerGenerator) (f []*File, e error) {
pg := gen.NewPackageGenerator()
ctors, ext, disj, extBy, globalVar, initFn := pg.RootDefinitions(vocabName, v.Manager, v.typeArray(), v.propArray())
initFile := jen.NewFilePath(pkg.Path())
initFile.Add(globalVar).Line().Add(initFn.Definition()).Line()
f = append(f, &File{
F: initFile,
FileName: "gen_init.go",
Directory: pkg.WriteDir(),
})
ctors, ext, disj, extBy := pg.RootDefinitions(vocabName, m, v.typeArray(), v.propArray())
lowerVocabName := strings.ToLower(vocabName)
f = append(f, funcsToFile(pkg, ctors, fmt.Sprintf("gen_pkg_%s_constructors.go", lowerVocabName)))
f = append(f, funcsToFile(pkg, ext, fmt.Sprintf("gen_pkg_%s_extends.go", lowerVocabName)))
@ -780,6 +824,21 @@ func (c Converter) rootFiles(pkg gen.Package, vocabName string, v vocabulary) (f
return
}
// initFile creates the file with the init function that hooks together the
// runtime Manager.
func (c Converter) initFile(pkg gen.Package, root vocabulary) (f *File, e error) {
pg := gen.NewPackageGenerator()
globalVar, initFn := pg.InitDefinitions(pkg, root.allTypeArray(), root.allPropArray())
initFile := jen.NewFilePath(pkg.Path())
initFile.Add(globalVar).Line().Add(initFn.Definition()).Line()
f = &File{
F: initFile,
FileName: "gen_init.go",
Directory: pkg.WriteDir(),
}
return
}
// packageFiles generates package-level files necessary for types and properties
// within a single vocabulary.
//

ファイルの表示

@ -171,8 +171,12 @@ func NewPackageGenerator() *PackageGenerator {
return &PackageGenerator{}
}
func (t *PackageGenerator) InitDefinitions(pkg Package, tgs []*TypeGenerator, pgs []*PropertyGenerator) (globalManager *jen.Statement, init *codegen.Function) {
return genInit(pkg, tgs, pgs)
}
// RootDefinitions creates functions needed at the root level of the package declarations.
func (t *PackageGenerator) RootDefinitions(vocabName string, m *ManagerGenerator, tgs []*TypeGenerator, pgs []*PropertyGenerator) (ctors, ext, disj, extBy []*codegen.Function, globalManager *jen.Statement, init *codegen.Function) {
func (t *PackageGenerator) RootDefinitions(vocabName string, m *ManagerGenerator, tgs []*TypeGenerator, pgs []*PropertyGenerator) (ctors, ext, disj, extBy []*codegen.Function) {
return rootDefinitions(vocabName, m, tgs, pgs)
}
@ -245,7 +249,7 @@ func publicTypeDefinitions(tgs []*TypeGenerator) (typeI *codegen.Interface) {
// rootDefinitions creates common functions needed at the root level of the
// package declarations.
func rootDefinitions(vocabName string, m *ManagerGenerator, tgs []*TypeGenerator, pgs []*PropertyGenerator) (ctors, ext, disj, extBy []*codegen.Function, globalManager *jen.Statement, init *codegen.Function) {
func rootDefinitions(vocabName string, m *ManagerGenerator, tgs []*TypeGenerator, pgs []*PropertyGenerator) (ctors, ext, disj, extBy []*codegen.Function) {
// Type constructors
for _, tg := range tgs {
ctors = append(ctors, codegen.NewCommentedFunction(
@ -308,17 +312,23 @@ func rootDefinitions(vocabName string, m *ManagerGenerator, tgs []*TypeGenerator
},
fmt.Sprintf("%s returns true if the other's type extends from %s.", name, tg.TypeName())))
}
return
}
// init generates the code that implements the init calls per-type and
// per-property package, so that the Manager is injected at runtime.
func genInit(pkg Package, tgs []*TypeGenerator, pgs []*PropertyGenerator) (globalManager *jen.Statement, init *codegen.Function) {
// init
globalManager = jen.Var().Id(managerInitName()).Op("*").Qual(m.pkg.Path(), managerName)
globalManager = jen.Var().Id(managerInitName()).Op("*").Qual(pkg.Path(), managerName)
callInitsMap := make(map[string]jen.Code, len(tgs))
for _, tg := range tgs {
callInitsMap[tg.PrivatePackage().Path()] = jen.Qual(tg.PrivatePackage().Path(), setManagerFunctionName).Call(
jen.Qual(m.pkg.Path(), managerInitName()),
jen.Qual(pkg.Path(), managerInitName()),
)
}
for _, pg := range pgs {
callInitsMap[pg.GetPrivatePackage().Path()] = jen.Qual(pg.GetPrivatePackage().Path(), setManagerFunctionName).Call(
jen.Qual(m.pkg.Path(), managerInitName()),
jen.Qual(pkg.Path(), managerInitName()),
)
}
callInits := make([]jen.Code, 0, len(callInitsMap))
@ -326,12 +336,12 @@ func rootDefinitions(vocabName string, m *ManagerGenerator, tgs []*TypeGenerator
callInits = append(callInits, c)
}
init = codegen.NewCommentedFunction(
m.pkg.Path(),
pkg.Path(),
"init",
/*params=*/ nil,
/*ret=*/ nil,
append([]jen.Code{
jen.Qual(m.pkg.Path(), managerInitName()).Op("=").Op("&").Qual(m.pkg.Path(), managerName).Values(),
jen.Qual(pkg.Path(), managerInitName()).Op("=").Op("&").Qual(pkg.Path(), managerName).Values(),
}, callInits...),
fmt.Sprintf("init handles the 'magic' of creating a %s and dependency-injecting it into every other code-generated package. This gives the implementations access to create any type needed to deserialize, without relying on the other specific concrete implementations. In order to replace a go-fed created type with your own, be sure to have the manager call your own implementation's deserialize functions instead of the built-in type. Finally, each implementation views the %s as an interface with only a subset of funcitons available. This means this %s implements the union of those interfaces.", managerName, managerName, managerName))
return