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. // typeArray converts Types to an array.
func (v vocabulary) typeArray() []*gen.TypeGenerator { func (v vocabulary) typeArray() []*gen.TypeGenerator {
tg := make([]*gen.TypeGenerator, 0, len(v.Types)) 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 // convertToFiles takes the generators for a vocabulary and maps them into a
// file structure. // file structure.
func (c Converter) convertToFiles(v vocabulary) (f []*File, e error) { func (c Converter) convertToFiles(v vocabulary) (f []*File, e error) {
// Values -- include all referenced values too. pub := c.GenRoot.PublicPackage()
for _, v := range v.Values { // References
pkg := c.valuePackage(v)
f = append(f, convertValue(pkg, v))
}
for _, ref := range v.References { for _, ref := range v.References {
for _, v := range ref.Values { for _, v := range ref.Values {
pkg := c.valuePackage(v) pkg := c.valuePackage(v)
@ -218,6 +258,22 @@ func (c Converter) convertToFiles(v vocabulary) (f []*File, e error) {
return return
} }
f = append(f, files...) 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 var files []*File
files, e = c.toFiles(v) files, e = c.toFiles(v)
@ -225,26 +281,32 @@ func (c Converter) convertToFiles(v vocabulary) (f []*File, e error) {
return return
} }
f = append(f, files...) 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) pkgFiles, err := c.packageFiles(v)
if err != nil { if err != nil {
e = err e = err
return return
} }
f = append(f, pkgFiles...) f = append(f, pkgFiles...)
// Manager // Init file
pub := c.GenRoot.PublicPackage() var file *File
file := jen.NewFilePath(pub.Path()) file, e = c.initFile(pub, v)
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)
if e != nil { if e != nil {
return 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 // Root Package Documentation
rootDocFile := jen.NewFilePath(pub.Path()) rootDocFile := jen.NewFilePath(pub.Path())
rootDocFile.PackageComment(gen.GenRootPackageComment(pub.Name())) 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. // convertGenRoot creates code-wide code generators.
func (c Converter) convertGenRoot(v *vocabulary) (e error) { 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( v.Manager, e = gen.NewManagerGenerator(
c.GenRoot.PublicPackage(), c.GenRoot.PublicPackage(),
typeArray, v.allTypeArray(),
funcPropArray, v.allFuncPropArray(),
nonFuncPropArray) v.allNonFuncPropArray())
return 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 // rootFiles creates files that are applied for all vocabularies. These files
// are the ones typically used by developers. // 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() pg := gen.NewPackageGenerator()
ctors, ext, disj, extBy, globalVar, initFn := pg.RootDefinitions(vocabName, v.Manager, v.typeArray(), v.propArray()) ctors, ext, disj, extBy := pg.RootDefinitions(vocabName, m, 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(),
})
lowerVocabName := strings.ToLower(vocabName) lowerVocabName := strings.ToLower(vocabName)
f = append(f, funcsToFile(pkg, ctors, fmt.Sprintf("gen_pkg_%s_constructors.go", lowerVocabName))) 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))) 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 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 // packageFiles generates package-level files necessary for types and properties
// within a single vocabulary. // within a single vocabulary.
// //

ファイルの表示

@ -171,8 +171,12 @@ func NewPackageGenerator() *PackageGenerator {
return &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. // 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) 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 // rootDefinitions creates common functions needed at the root level of the
// package declarations. // 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 // Type constructors
for _, tg := range tgs { for _, tg := range tgs {
ctors = append(ctors, codegen.NewCommentedFunction( 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()))) 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 // 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)) callInitsMap := make(map[string]jen.Code, len(tgs))
for _, tg := range tgs { for _, tg := range tgs {
callInitsMap[tg.PrivatePackage().Path()] = jen.Qual(tg.PrivatePackage().Path(), setManagerFunctionName).Call( 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 { for _, pg := range pgs {
callInitsMap[pg.GetPrivatePackage().Path()] = jen.Qual(pg.GetPrivatePackage().Path(), setManagerFunctionName).Call( 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)) callInits := make([]jen.Code, 0, len(callInitsMap))
@ -326,12 +336,12 @@ func rootDefinitions(vocabName string, m *ManagerGenerator, tgs []*TypeGenerator
callInits = append(callInits, c) callInits = append(callInits, c)
} }
init = codegen.NewCommentedFunction( init = codegen.NewCommentedFunction(
m.pkg.Path(), pkg.Path(),
"init", "init",
/*params=*/ nil, /*params=*/ nil,
/*ret=*/ nil, /*ret=*/ nil,
append([]jen.Code{ 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...), }, 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)) 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 return