From d7e4028437a4ab75f103471fdf911b503834af80 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Wed, 11 May 2016 17:41:55 -0700 Subject: [PATCH] modify generators --- .../conversion-gen/generators/conversion.go | 90 ++++++++----------- .../deepcopy-gen/generators/deepcopy.go | 77 ++++++++-------- cmd/libs/go2idl/generator/snippet_writer.go | 27 +++++- cmd/libs/go2idl/types/types.go | 9 ++ 4 files changed, 109 insertions(+), 94 deletions(-) diff --git a/cmd/libs/go2idl/conversion-gen/generators/conversion.go b/cmd/libs/go2idl/conversion-gen/generators/conversion.go index f9e317005bc..b28c1c133e5 100644 --- a/cmd/libs/go2idl/conversion-gen/generators/conversion.go +++ b/cmd/libs/go2idl/conversion-gen/generators/conversion.go @@ -104,8 +104,8 @@ type conversionFuncMap map[conversionPair]*types.Type // Returns all manually-defined conversion functions in the package. func getManualConversionFunctions(context *generator.Context, pkg *types.Package, manualMap conversionFuncMap) { - scopeName := types.Name{Package: conversionPackagePath, Name: "Scope"} - errorName := types.Name{Package: "", Name: "error"} + scopeName := types.Ref(conversionPackagePath, "Scope").Name + errorName := types.Ref("", "error").Name buffer := &bytes.Buffer{} sw := generator.NewSnippetWriter(buffer, context, "$", "$") @@ -409,8 +409,6 @@ type genConversion struct { manualDefaulters defaulterFuncMap imports namer.ImportTracker typesForInit []conversionPair - - globalVariables map[string]interface{} } func NewGenConversion(sanitizedName, targetPackage string, manualConversions conversionFuncMap, manualDefaulters defaulterFuncMap, peerPkgs []string) generator.Generator { @@ -429,7 +427,23 @@ func NewGenConversion(sanitizedName, targetPackage string, manualConversions con func (g *genConversion) Namers(c *generator.Context) namer.NameSystems { // Have the raw namer for this file track what it imports. - return namer.NameSystems{"raw": namer.NewRawNamer(g.targetPackage, g.imports)} + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.targetPackage, g.imports), + "publicIT": &namerPlusImportTracking{ + delegate: conversionNamer(), + tracker: g.imports, + }, + } +} + +type namerPlusImportTracking struct { + delegate namer.Namer + tracker namer.ImportTracker +} + +func (n *namerPlusImportTracking) Name(t *types.Type) string { + n.tracker.AddType(t) + return n.delegate.Name(t) } func (g *genConversion) convertibleOnlyWithinPackage(inType, outType *types.Type) bool { @@ -506,33 +520,20 @@ func (g *genConversion) Imports(c *generator.Context) (imports []string) { return importLines } -func (g *genConversion) withGlobals(args map[string]interface{}) map[string]interface{} { - for k, v := range g.globalVariables { - if _, ok := args[k]; !ok { - args[k] = v - } - } - return args -} - -func argsFromType(inType, outType *types.Type) map[string]interface{} { - return map[string]interface{}{ +func argsFromType(inType, outType *types.Type) generator.Args { + return generator.Args{ "inType": inType, "outType": outType, } } -func defaultingArgsFromType(inType *types.Type) interface{} { - return map[string]interface{}{ +func defaultingArgsFromType(inType *types.Type) generator.Args { + return generator.Args{ "inType": inType, } } -func (g *genConversion) funcNameTmpl(inType, outType *types.Type) string { - tmpl := "Convert_$.inType|public$_To_$.outType|public$" - g.imports.AddType(inType) - g.imports.AddType(outType) - return tmpl -} + +const nameTmpl = "Convert_$.inType|publicIT$_To_$.outType|publicIT$" func (g *genConversion) preexists(inType, outType *types.Type) (*types.Type, bool) { function, ok := g.manualConversions[conversionPair{inType, outType}] @@ -540,23 +541,15 @@ func (g *genConversion) preexists(inType, outType *types.Type) (*types.Type, boo } func (g *genConversion) Init(c *generator.Context, w io.Writer) error { - scheme := c.Universe.Variable(types.Name{Package: apiPackagePath, Name: "Scheme"}) - g.imports.AddType(scheme) - scope := c.Universe.Type(types.Name{Package: conversionPackagePath, Name: "Scope"}) - g.imports.AddType(scope) - g.globalVariables = map[string]interface{}{ - "scheme": scheme, - "Scope": scope, - } + scheme := c.Universe.Package(apiPackagePath).Variable("Scheme") sw := generator.NewSnippetWriter(w, c, "$", "$") sw.Do("func init() {\n", nil) - sw.Do("if err := $.scheme|raw$.AddGeneratedConversionFuncs(\n", map[string]interface{}{ + sw.Do("if err := $.scheme|raw$.AddGeneratedConversionFuncs(\n", generator.Args{ "scheme": scheme, }) for _, conv := range g.typesForInit { - funcName := g.funcNameTmpl(conv.inType, conv.outType) - sw.Do(fmt.Sprintf("%s,\n", funcName), argsFromType(conv.inType, conv.outType)) + sw.Do(nameTmpl+",\n", argsFromType(conv.inType, conv.outType)) } sw.Do("); err != nil {\n", nil) sw.Do("// if one of the conversion functions is malformed, detect it immediately.\n", nil) @@ -595,9 +588,10 @@ func (g *genConversion) GenerateType(c *generator.Context, t *types.Type, w io.W } func (g *genConversion) generateConversion(inType, outType *types.Type, sw *generator.SnippetWriter) { - funcName := g.funcNameTmpl(inType, outType) + args := argsFromType(inType, outType). + With("Scope", types.Ref(conversionPackagePath, "Scope")) - sw.Do(fmt.Sprintf("func auto%s(in *$.inType|raw$, out *$.outType|raw$, s $.Scope|raw$) error {\n", funcName), g.withGlobals(argsFromType(inType, outType))) + sw.Do("func auto"+nameTmpl+"(in *$.inType|raw$, out *$.outType|raw$, s $.Scope|raw$) error {\n", args) // if no defaulter of form SetDefaults_XXX is defined, do not inline a check for defaulting. if function, ok := g.manualDefaulters[inType]; ok { sw.Do("$.|raw$(in)\n", function) @@ -608,8 +602,8 @@ func (g *genConversion) generateConversion(inType, outType *types.Type, sw *gene // If there is no public manual Conversion method, generate it. if _, ok := g.preexists(inType, outType); !ok { - sw.Do(fmt.Sprintf("func %s(in *$.inType|raw$, out *$.outType|raw$, s $.Scope|raw$) error {\n", funcName), g.withGlobals(argsFromType(inType, outType))) - sw.Do(fmt.Sprintf("return auto%s(in, out, s)\n", funcName), argsFromType(inType, outType)) + sw.Do("func "+nameTmpl+"(in *$.inType|raw$, out *$.outType|raw$, s $.Scope|raw$) error {\n", args) + sw.Do("return auto"+nameTmpl+"(in, out, s)\n", args) sw.Do("}\n\n", nil) } } @@ -666,8 +660,7 @@ func (g *genConversion) doMap(inType, outType *types.Type, sw *generator.Snippet if function, ok := g.preexists(inType.Elem, outType.Elem); ok { sw.Do("if err := $.|raw$(&val, newVal, s); err != nil {\n", function) } else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) { - funcName := g.funcNameTmpl(inType.Elem, outType.Elem) - sw.Do(fmt.Sprintf("if err := %s(&val, newVal, s); err != nil {\n", funcName), argsFromType(inType.Elem, outType.Elem)) + sw.Do("if err := "+nameTmpl+"(&val, newVal, s); err != nil {\n", argsFromType(inType.Elem, outType.Elem)) } else { sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil) sw.Do("if err := s.Convert(&val, newVal, 0); err != nil {\n", nil) @@ -704,8 +697,7 @@ func (g *genConversion) doSlice(inType, outType *types.Type, sw *generator.Snipp if function, ok := g.preexists(inType.Elem, outType.Elem); ok { sw.Do("if err := $.|raw$(&(*in)[i], &(*out)[i], s); err != nil {\n", function) } else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) { - funcName := g.funcNameTmpl(inType.Elem, outType.Elem) - sw.Do(fmt.Sprintf("if err := %s(&(*in)[i], &(*out)[i], s); err != nil {\n", funcName), argsFromType(inType.Elem, outType.Elem)) + sw.Do("if err := "+nameTmpl+"(&(*in)[i], &(*out)[i], s); err != nil {\n", argsFromType(inType.Elem, outType.Elem)) } else { // TODO: This triggers on v1.ObjectMeta <-> api.ObjectMeta and // similar because neither package is the target package, and @@ -785,8 +777,7 @@ func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.Snip continue } if g.convertibleOnlyWithinPackage(t, outT) { - funcName := g.funcNameTmpl(t, outT) - sw.Do(fmt.Sprintf("if err := %s(&in.$.name$, &out.$.name$, s); err != nil {\n", funcName), args) + sw.Do("if err := "+nameTmpl+"(&in.$.name$, &out.$.name$, s); err != nil {\n", args) } else { sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil) sw.Do("if err := s.Convert(&in.$.name$, &out.$.name$, 0); err != nil {\n", args) @@ -802,8 +793,7 @@ func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.Snip } } else { if g.convertibleOnlyWithinPackage(t, outT) { - funcName := g.funcNameTmpl(t, outT) - sw.Do(fmt.Sprintf("if err := %s(&in.$.name$, &out.$.name$, s); err != nil {\n", funcName), args) + sw.Do("if err := "+nameTmpl+"(&in.$.name$, &out.$.name$, s); err != nil {\n", args) } else { sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil) sw.Do("if err := s.Convert(&in.$.name$, &out.$.name$, 0); err != nil {\n", args) @@ -813,8 +803,7 @@ func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.Snip } default: if g.convertibleOnlyWithinPackage(t, outT) { - funcName := g.funcNameTmpl(t, outT) - sw.Do(fmt.Sprintf("if err := %s(&in.$.name$, &out.$.name$, s); err != nil {\n", funcName), args) + sw.Do("if err := "+nameTmpl+"(&in.$.name$, &out.$.name$, s); err != nil {\n", args) } else { sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil) sw.Do("if err := s.Convert(&in.$.name$, &out.$.name$, 0); err != nil {\n", args) @@ -841,8 +830,7 @@ func (g *genConversion) doPointer(inType, outType *types.Type, sw *generator.Sni if function, ok := g.preexists(inType.Elem, outType.Elem); ok { sw.Do("if err := $.|raw$(*in, *out, s); err != nil {\n", function) } else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) { - funcName := g.funcNameTmpl(inType.Elem, outType.Elem) - sw.Do(fmt.Sprintf("if err := %s(*in, *out, s); err != nil {\n", funcName), argsFromType(inType.Elem, outType.Elem)) + sw.Do("if err := "+nameTmpl+"(*in, *out, s); err != nil {\n", argsFromType(inType.Elem, outType.Elem)) } else { sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil) sw.Do("if err := s.Convert(*in, *out, 0); err != nil {\n", nil) diff --git a/cmd/libs/go2idl/deepcopy-gen/generators/deepcopy.go b/cmd/libs/go2idl/deepcopy-gen/generators/deepcopy.go index 02eb764912a..b8f256615f4 100644 --- a/cmd/libs/go2idl/deepcopy-gen/generators/deepcopy.go +++ b/cmd/libs/go2idl/deepcopy-gen/generators/deepcopy.go @@ -216,8 +216,6 @@ type genDeepCopy struct { registerTypes bool imports namer.ImportTracker typesForInit []*types.Type - - globalVariables map[string]interface{} } func NewGenDeepCopy(sanitizedName, targetPackage string, boundingDirs []string, allTypes, registerTypes bool) generator.Generator { @@ -236,7 +234,14 @@ func NewGenDeepCopy(sanitizedName, targetPackage string, boundingDirs []string, func (g *genDeepCopy) Namers(c *generator.Context) namer.NameSystems { // Have the raw namer for this file track what it imports. - return namer.NameSystems{"raw": namer.NewRawNamer(g.targetPackage, g.imports)} + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.targetPackage, g.imports), + "dcFnName": &dcFnNamer{ + public: deepCopyNamer(), + tracker: g.imports, + myPackage: g.targetPackage, + }, + } } func (g *genDeepCopy) Filter(c *generator.Context, t *types.Type) bool { @@ -338,36 +343,30 @@ func (g *genDeepCopy) Imports(c *generator.Context) (imports []string) { return importLines } -func (g *genDeepCopy) withGlobals(args map[string]interface{}) map[string]interface{} { - for k, v := range g.globalVariables { - if _, ok := args[k]; !ok { - args[k] = v - } - } - return args -} - -func argsFromType(t *types.Type) map[string]interface{} { - return map[string]interface{}{ +func argsFromType(t *types.Type) generator.Args { + return generator.Args{ "type": t, } } -func (g *genDeepCopy) funcNameTmpl(t *types.Type) string { - tmpl := "DeepCopy_$.type|public$" - g.imports.AddType(t) - if t.Name.Package != g.targetPackage { - tmpl = g.imports.LocalNameOf(t.Name.Package) + "." + tmpl +type dcFnNamer struct { + public namer.Namer + tracker namer.ImportTracker + myPackage string +} + +func (n *dcFnNamer) Name(t *types.Type) string { + pubName := n.public.Name(t) + n.tracker.AddType(t) + if t.Name.Package == n.myPackage { + return "DeepCopy_" + pubName } - return tmpl + return fmt.Sprintf("%s.DeepCopy_%s", n.tracker.LocalNameOf(t.Name.Package), pubName) } func (g *genDeepCopy) Init(c *generator.Context, w io.Writer) error { cloner := c.Universe.Type(types.Name{Package: conversionPackagePath, Name: "Cloner"}) g.imports.AddType(cloner) - g.globalVariables = map[string]interface{}{ - "Cloner": cloner, - } if !g.registerTypes { // TODO: We should come up with a solution to register all generated // deep-copy functions. However, for now, to avoid import cycles @@ -377,18 +376,15 @@ func (g *genDeepCopy) Init(c *generator.Context, w io.Writer) error { glog.V(5).Infof("registering types in pkg %q", g.targetPackage) scheme := c.Universe.Variable(types.Name{Package: apiPackagePath, Name: "Scheme"}) - g.imports.AddType(scheme) - g.globalVariables["scheme"] = scheme - sw := generator.NewSnippetWriter(w, c, "$", "$") sw.Do("func init() {\n", nil) - sw.Do("if err := $.scheme|raw$.AddGeneratedDeepCopyFuncs(\n", map[string]interface{}{ + sw.Do("if err := $.scheme|raw$.AddGeneratedDeepCopyFuncs(\n", generator.Args{ "scheme": scheme, }) - reflect := c.Universe.Type(types.Name{Package: "reflect", Name: "TypeOf"}) for _, t := range g.typesForInit { - g.imports.AddType(reflect) - sw.Do(fmt.Sprintf("conversion.GeneratedDeepCopyFunc{Fn: %s, InType: reflect.TypeOf(&$.type|raw${})},\n", g.funcNameTmpl(t)), argsFromType(t)) + args := argsFromType(t). + With("typeof", c.Universe.Package("reflect").Function("TypeOf")) + sw.Do("conversion.GeneratedDeepCopyFunc{Fn: $.type|dcFnName$, InType: $.typeof|raw$(&$.type|raw${})},\n", args) } sw.Do("); err != nil {\n", nil) sw.Do("// if one of the deep copy functions is malformed, detect it immediately.\n", nil) @@ -427,9 +423,10 @@ func (g *genDeepCopy) GenerateType(c *generator.Context, t *types.Type, w io.Wri glog.V(5).Infof("generating for type %v", t) sw := generator.NewSnippetWriter(w, c, "$", "$") - funcName := g.funcNameTmpl(t) - sw.Do(fmt.Sprintf("func %s(in interface{}, out interface{}, c *$.Cloner|raw$) error {{\n", funcName), g.withGlobals(argsFromType(t))) - sw.Do("in := in.(*$.type|raw$)\nout := out.(*$.type|raw$)\n", g.withGlobals(argsFromType(t))) + args := argsFromType(t). + With("clonerType", types.Ref(conversionPackagePath, "Cloner")) + sw.Do("func $.type|dcFnName$(in interface{}, out interface{}, c *$.clonerType|raw$) error {{\n", args) + sw.Do("in := in.(*$.type|raw$)\nout := out.(*$.type|raw$)\n", argsFromType(t)) g.generateFor(t, sw) sw.Do("return nil\n", nil) sw.Do("}}\n\n", nil) @@ -486,8 +483,7 @@ func (g *genDeepCopy) doMap(t *types.Type, sw *generator.SnippetWriter) { sw.Do("for key, val := range *in {\n", nil) if g.copyableAndInBounds(t.Elem) { sw.Do("newVal := new($.|raw$)\n", t.Elem) - funcName := g.funcNameTmpl(t.Elem) - sw.Do(fmt.Sprintf("if err := %s(&val, newVal, c); err != nil {\n", funcName), argsFromType(t.Elem)) + sw.Do("if err := $.type|dcFnName$(&val, newVal, c); err != nil {\n", argsFromType(t.Elem)) sw.Do("return err\n", nil) sw.Do("}\n", nil) sw.Do("(*out)[key] = *newVal\n", nil) @@ -519,8 +515,7 @@ func (g *genDeepCopy) doSlice(t *types.Type, sw *generator.SnippetWriter) { } else if t.Elem.IsAssignable() { sw.Do("(*out)[i] = (*in)[i]\n", nil) } else if g.copyableAndInBounds(t.Elem) { - funcName := g.funcNameTmpl(t.Elem) - sw.Do(fmt.Sprintf("if err := %s(&(*in)[i], &(*out)[i], c); err != nil {\n", funcName), argsFromType(t.Elem)) + sw.Do("if err := $.type|dcFnName$(&(*in)[i], &(*out)[i], c); err != nil {\n", argsFromType(t.Elem)) sw.Do("return err\n", nil) sw.Do("}\n", nil) } else { @@ -546,7 +541,7 @@ func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) { copied.Name = t.Name t = &copied } - args := map[string]interface{}{ + args := generator.Args{ "type": t, "name": m.Name, } @@ -566,8 +561,7 @@ func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) { } else if t.IsAssignable() { sw.Do("out.$.name$ = in.$.name$\n", args) } else if g.copyableAndInBounds(t) { - funcName := g.funcNameTmpl(t) - sw.Do(fmt.Sprintf("if err := %s(&in.$.name$, &out.$.name$, c); err != nil {\n", funcName), args) + sw.Do("if err := $.type|dcFnName$(&in.$.name$, &out.$.name$, c); err != nil {\n", args) sw.Do("return err\n", nil) sw.Do("}\n", nil) } else { @@ -602,9 +596,8 @@ func (g *genDeepCopy) doPointer(t *types.Type, sw *generator.SnippetWriter) { sw.Do("*out = new($.Elem|raw$)\n", t) sw.Do("**out = **in", nil) } else if g.copyableAndInBounds(t.Elem) { - funcName := g.funcNameTmpl(t.Elem) sw.Do("*out = new($.Elem|raw$)\n", t) - sw.Do(fmt.Sprintf("if err := %s(*in, *out, c); err != nil {\n", funcName), argsFromType(t.Elem)) + sw.Do("if err := $.type|dcFnName$(*in, *out, c); err != nil {\n", argsFromType(t.Elem)) sw.Do("return err\n", nil) sw.Do("}\n", nil) } else { diff --git a/cmd/libs/go2idl/generator/snippet_writer.go b/cmd/libs/go2idl/generator/snippet_writer.go index f1cbac01c96..eae917c1381 100644 --- a/cmd/libs/go2idl/generator/snippet_writer.go +++ b/cmd/libs/go2idl/generator/snippet_writer.go @@ -94,7 +94,7 @@ func NewSnippetWriter(w io.Writer, c *Context, left, right string) *SnippetWrite // but you should consider doing the logic in go and stitching them together // for the sake of your readers. // -// TODO: Change Do() to optionally take a list of pairt of parameters (key, value) +// TODO: Change Do() to optionally take a list of pairs of parameters (key, value) // and have it construct a combined map with that and args. func (s *SnippetWriter) Do(format string, args interface{}) *SnippetWriter { if s.err != nil { @@ -119,6 +119,31 @@ func (s *SnippetWriter) Do(format string, args interface{}) *SnippetWriter { return s } +// Args exists to make it convenient to construct arguments for +// SnippetWriter.Do. +type Args map[interface{}]interface{} + +// With makes a copy of a and adds the given key, value pair. +func (a Args) With(key, value interface{}) Args { + a2 := Args{key: value} + for k, v := range a { + a2[k] = v + } + return a2 +} + +// WithArgs makes a copy of a and adds the given arguments. +func (a Args) WithArgs(rhs Args) Args { + a2 := Args{} + for k, v := range rhs { + a2[k] = v + } + for k, v := range a { + a2[k] = v + } + return a2 +} + func (s *SnippetWriter) Out() io.Writer { return s.w } diff --git a/cmd/libs/go2idl/types/types.go b/cmd/libs/go2idl/types/types.go index 2853a246b8b..89523433e7d 100644 --- a/cmd/libs/go2idl/types/types.go +++ b/cmd/libs/go2idl/types/types.go @@ -16,6 +16,15 @@ limitations under the License. package types +// Ref makes a reference to the given type. It can only be used for e.g. +// passing to namers. +func Ref(packageName, typeName string) *Type { + return &Type{Name: Name{ + Name: typeName, + Package: packageName, + }} +} + // A type name may have a package qualifier. type Name struct { // Empty if embedded or builtin. This is the package path unless Path is specified.