123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- package generator
- import (
- "bytes"
- "io"
- "go-common/app/tool/gengo/namer"
- "go-common/app/tool/gengo/parser"
- "go-common/app/tool/gengo/types"
- )
- // Package contains the contract for generating a package.
- type Package interface {
- // Name returns the package short name.
- Name() string
- // Path returns the package import path.
- Path() string
- // Filter should return true if this package cares about this type.
- // Otherwise, this type will be omitted from the type ordering for
- // this package.
- Filter(*Context, *types.Type) bool
- // Header should return a header for the file, including comment markers.
- // Useful for copyright notices and doc strings. Include an
- // autogeneration notice! Do not include the "package x" line.
- Header(filename string) []byte
- // Generators returns the list of generators for this package. It is
- // allowed for more than one generator to write to the same file.
- // A Context is passed in case the list of generators depends on the
- // input types.
- Generators(*Context) []Generator
- }
- // File is
- type File struct {
- Name string
- FileType string
- PackageName string
- Header []byte
- Imports map[string]struct{}
- Vars bytes.Buffer
- Consts bytes.Buffer
- Body bytes.Buffer
- }
- // FileType is
- type FileType interface {
- AssembleFile(f *File, path string) error
- VerifyFile(f *File, path string) error
- }
- // Packages is a list of packages to generate.
- type Packages []Package
- // Generator is the contract for anything that wants to do auto-generation.
- // It's expected that the io.Writers passed to the below functions will be
- // ErrorTrackers; this allows implementations to not check for io errors,
- // making more readable code.
- //
- // The call order for the functions that take a Context is:
- // 1. Filter() // Subsequent calls see only types that pass this.
- // 2. Namers() // Subsequent calls see the namers provided by this.
- // 3. PackageVars()
- // 4. PackageConsts()
- // 5. Init()
- // 6. GenerateType() // Called N times, once per type in the context's Order.
- // 7. Imports()
- //
- // You may have multiple generators for the same file.
- type Generator interface {
- // The name of this generator. Will be included in generated comments.
- Name() string
- // Filter should return true if this generator cares about this type.
- // (otherwise, GenerateType will not be called.)
- //
- // Filter is called before any of the generator's other functions;
- // subsequent calls will get a context with only the types that passed
- // this filter.
- Filter(*Context, *types.Type) bool
- // If this generator needs special namers, return them here. These will
- // override the original namers in the context if there is a collision.
- // You may return nil if you don't need special names. These names will
- // be available in the context passed to the rest of the generator's
- // functions.
- //
- // A use case for this is to return a namer that tracks imports.
- Namers(*Context) namer.NameSystems
- // Init should write an init function, and any other content that's not
- // generated per-type. (It's not intended for generator specific
- // initialization! Do that when your Package constructs the
- // Generators.)
- Init(*Context, io.Writer) error
- // Finalize should write finish up functions, and any other content that's not
- // generated per-type.
- Finalize(*Context, io.Writer) error
- // PackageVars should emit an array of variable lines. They will be
- // placed in a var ( ... ) block. There's no need to include a leading
- // \t or trailing \n.
- PackageVars(*Context) []string
- // PackageConsts should emit an array of constant lines. They will be
- // placed in a const ( ... ) block. There's no need to include a leading
- // \t or trailing \n.
- PackageConsts(*Context) []string
- // GenerateType should emit the code for a particular type.
- GenerateType(*Context, *types.Type, io.Writer) error
- // Imports should return a list of necessary imports. They will be
- // formatted correctly. You do not need to include quotation marks,
- // return only the package name; alternatively, you can also return
- // imports in the format `name "path/to/pkg"`. Imports will be called
- // after Init, PackageVars, PackageConsts, and GenerateType, to allow
- // you to keep track of what imports you actually need.
- Imports(*Context) []string
- // Preferred file name of this generator, not including a path. It is
- // allowed for multiple generators to use the same filename, but it's
- // up to you to make sure they don't have colliding import names.
- // TODO: provide per-file import tracking, removing the requirement
- // that generators coordinate..
- Filename() string
- // A registered file type in the context to generate this file with. If
- // the FileType is not found in the context, execution will stop.
- FileType() string
- }
- // Context is global context for individual generators to consume.
- type Context struct {
- // A map from the naming system to the names for that system. E.g., you
- // might have public names and several private naming systems.
- Namers namer.NameSystems
- // All the types, in case you want to look up something.
- Universe types.Universe
- // All the user-specified packages. This is after recursive expansion.
- Inputs []string
- // The canonical ordering of the types (will be filtered by both the
- // Package's and Generator's Filter methods).
- Order []*types.Type
- // A set of types this context can process. If this is empty or nil,
- // the default "golang" filetype will be provided.
- FileTypes map[string]FileType
- // If true, Execute* calls will just verify that the existing output is
- // correct. (You may set this after calling NewContext.)
- Verify bool
- // Allows generators to add packages at runtime.
- builder *parser.Builder
- }
- // NewContext generates a context from the given builder, naming systems, and
- // the naming system you wish to construct the canonical ordering from.
- func NewContext(b *parser.Builder, nameSystems namer.NameSystems, canonicalOrderName string) (*Context, error) {
- universe, err := b.FindTypes()
- if err != nil {
- return nil, err
- }
- c := &Context{
- Namers: namer.NameSystems{},
- Universe: universe,
- Inputs: b.FindPackages(),
- FileTypes: map[string]FileType{
- GolangFileType: NewGolangFile(),
- },
- builder: b,
- }
- for name, systemNamer := range nameSystems {
- c.Namers[name] = systemNamer
- if name == canonicalOrderName {
- orderer := namer.Orderer{Namer: systemNamer}
- c.Order = orderer.OrderUniverse(universe)
- }
- }
- return c, nil
- }
- // AddDir adds a Go package to the context. The specified path must be a single
- // go package import path. GOPATH, GOROOT, and the location of your go binary
- // (`which go`) will all be searched, in the normal Go fashion.
- // Deprecated. Please use AddDirectory.
- func (ctxt *Context) AddDir(path string) error {
- return ctxt.builder.AddDirTo(path, &ctxt.Universe)
- }
- // AddDirectory adds a Go package to the context. The specified path must be a
- // single go package import path. GOPATH, GOROOT, and the location of your go
- // binary (`which go`) will all be searched, in the normal Go fashion.
- func (ctxt *Context) AddDirectory(path string) (*types.Package, error) {
- return ctxt.builder.AddDirectoryTo(path, &ctxt.Universe)
- }
|