-- import "github.com/metaleap/go-gent"
Package gent offers a Golang code-gen toolkit; philosophy being:
- "your package's type-defs. your pluggable custom code-gen logics (+ many
built-in ones), tuned via your struct-field tags. one
go generate
call."
The design idea is that your codegen programs remains your own main
packages
written by you, but importing gent
keeps them short and high-level: fast and
simple to write, iterate, maintain over time. Furthermore (unlike unwieldy
config-file-formats or 100s-of-cmd-args) this approach grants Turing-complete
control over fine-tuning the code-gen flow to only generate what's truly needed,
rather than "every possible func for every possible type-def", to minimize both
codegen and your compilation times.
Focus at the beginning is strictly on generating func
s and methods for a
package's existing type-defs, not generating type-defs such as struct
s.
For building the AST of the to-be-emitted Go source file:
-
gent
relies on mygithub.com/go-leap/dev/go/gen
package -
and so do the built-in code-gens under
github.com/metaleap/go-gent/gents/*
, -
but your custom
gent.IGent
implementers are free to prefer other approaches (such astext/template
orgithub.com/dave/jennifer
or hard-coded string-building or other) by having theirGenerateTopLevelDecls
implementation return agithub.com/go-leap/dev/go/gen.SynRaw
-typed byte-array.
Very WIP: more comprehensive readme / package docs to come.
var (
CodeGenCommentNotice Str = "DON'T EDIT: code gen'd with `{progName}` using `github.com/metaleap/go-gent`"
CodeGenCommentProgName = filepath.Base(os.Args[0])
Defaults struct {
CtxOpt CtxOpts
}
OnBeforeLoad func(*Pkg)
)
type Ctx struct {
// options pertaining to this `Ctx`
Opt CtxOpts
// strictly read-only
Pkg *Pkg
ExtraDefs []*udevgogen.SynFunc
Gents Gents
}
Ctx is a codegen-time context during a Pkg.RunGents
call and is passed to
IGent.GenerateTopLevelDecls
.
func (me *Ctx) DeclsGeneratedSoFar(maybeGent IGent, maybeType *Type) (matches []udevgogen.Syns)
DeclsGeneratedSoFar collects and returns all results of
IGent.GenerateTopLevelDecls
performed so far by this Ctx
, filtered
optionally by IGent
and/or by Type
.
func (me *Ctx) GentExistsFor(t *Type, check func(IGent) bool) bool
func (me *Ctx) Import(pkgImportPath string) (pkgImportName udevgogen.PkgName)
Import returns the pkgImportName
for the specified pkgImportPath
. Eg.
Import("encoding/json")
might return pkg__encoding_json
and more
importantly, the import will be properly emitted (only if any of the import's
uses get emitted) at code-gen time. Import is a Ctx
-local wrapper of the
github.com/go-leap/dev/go/gen.PkgImports.Ensure
method.
func (me *Ctx) MayGentRunForType(g IGent, t *Type) bool
func (me *Ctx) N(pref string) udevgogen.Named
type CtxOpts struct {
// For `Defaults.CtxOpts`, initialized from env-var
// `GOGENT_NOGOFMT` if `strconv.ParseBool`able.
NoGoFmt bool
// For `Defaults.CtxOpts`, initialized from env-var
// `GOGENT_EMITNOOPS` if `strconv.ParseBool`able.
EmitNoOpFuncBodies bool
// If set, can be used to prevent running of the given
// (or any) `IGent` on the given (or any) `*Type`.
// See also `IGent.Opt().MayRunForType`.
MayGentRunForType func(IGent, *Type) bool
// For `Defaults.CtxOpts`, initially set to `"__gent__"`.
HelpersPrefix string
}
CtxOpts wraps Ctx
options.
type Gents []IGent
Gents is a slice if IGent
s.
func (me Gents) EnableOrDisableAll(enabled bool)
EnableOrDisableAll sets all IGent.Opt().Disabled
fields to !enabled
.
func (me Gents) EnableOrDisableAllVariantsAndOptionals(enabled bool)
EnableOrDisableAllVariantsAndOptionals calls the same-named method on all
IGent
s in me
.
func (me Gents) With(gents ...Gents) (merged Gents)
With merges all IGent
s in me
with all those in gents
into merged
.
type IGent interface {
// must never return `nil` (easiest impl is to embed `Opts`)
Opt() *Opts
// implemented as a no-op by `Opts`, to be
// overridden by implementations as desired
EnableOrDisableAllVariantsAndOptionals(bool)
// may read from but never mutate its args.
// expected to generate preferentially funcs / methods
// instead of top-level const / var / type decls
GenerateTopLevelDecls(*Ctx, *Type) udevgogen.Syns
}
IGent is the interface implemented by individual code-gens.
type Opts struct {
Disabled bool
EmitCommented bool
// not used by `go-gent`, but could be handy for callers
Name string
// tested right after `Disabled` and before the below checks.
// should typically be false for most `Gent`s as the design assumes
// generation of methods, but it's for the occasional need to generate
// non-method `func`s related to certain type-alias declarations
RunOnlyForTypeAliases bool
RunOnlyOnceWithoutAnyType bool
// if-and-only-if these are set, they're checked
// before `MayRunForType` (but after `Disabled`)
RunNeverForTypes, RunOnlyForTypes struct {
Named []string
Satisfying func(*Ctx, *Type) bool
}
// If set, can be used to prevent running of
// this `IGent` on the given (or any) `*Type`.
// See also `CtxOpts.MayGentRunForType`.
MayRunForType func(*Ctx, *Type) bool
}
Opts related to a single IGent
, and designed for embedding.
func (me *Opts) EnableOrDisableAllVariantsAndOptionals(bool)
EnableOrDisableAllVariantsAndOptionals implements IGent
but with a no-op, to
be overridden by Opts
-embedders as desired.
To disable or enable an IGent
itself, set Opts.Disabled
.
func (me *Opts) Opt() *Opts
Opt implements IGent.Opt()
for Opts
embedders.
type Pkg struct {
PkgSpec
DirPath string
GoFileNames []string
Loaded struct {
Prog *loader.Program
Info *loader.PackageInfo
}
Types Types
CodeGen struct {
OutputFile struct {
Name string
DocComments udevgogen.SingleLineDocCommentParagraphs
}
}
}
func LoadPkg(pkgImportPathOrFileSystemPath string, outputFileName string, dontLoadButJustInitUsingPkgNameInstead string) (me *Pkg, err error)
func MustLoadPkg(pkgImportPathOrFileSystemPath string, outputFileName string) *Pkg
func TryExtPkg(pkgImpPath string) (extPkg *Pkg)
func (me *Pkg) DirName() string
func (me *Pkg) RunGents(maybeCtxOpts *CtxOpts, gents Gents) (src []byte, stats *Stats, err error)
RunGents instructs the given gents
to generate code for me
.
func (me *Pkg) RunGentsAndGenerateOutputFile(maybeCtxOpts *CtxOpts, gents Gents) (*Stats, error)
type PkgSpec struct {
Name string
ImportPath string
}
type Pkgs map[string]*Pkg
func LoadPkgs(pkgPathsWithOutputFileNames map[string]string) (Pkgs, error)
func MustLoadPkgs(pkgPathsWithOutputFileNames map[string]string) Pkgs
func (me Pkgs) MustRunGentsAndGenerateOutputFiles(maybeCtxOpts *CtxOpts, gents Gents) (timeTakenTotal time.Duration, statsPerPkg map[*Pkg]*Stats)
MustRunGentsAndGenerateOutputFiles calls RunGents
on the Pkg
s in me
.
func (me Pkgs) RunGentsAndGenerateOutputFiles(maybeCtxOpts *CtxOpts, gents Gents) (timeTakenTotal time.Duration, statsPerPkg map[*Pkg]*Stats, errs map[*Pkg]error)
RunGentsAndGenerateOutputFiles calls RunGents
on the Pkg
s in me
.
type Rename func(*Ctx, *Type, string) string
type Stats struct {
DurationOf struct {
Constructing time.Duration
Emitting time.Duration
Formatting time.Duration
Everything time.Duration
}
}
type Str string
func (me Str) With(placeholderNamesAndValues ...string) string
type Type struct {
Pkg *Pkg
SrcFileImports []PkgSpec
Name string
Alias bool
// Expr is whatever underlying-type this type-decl represents, that is:
// of the original `type foo bar` or `type foo = bar` declaration,
// this `Type` is the `foo` identity and its `Expr` captures the `bar`.
Expr struct {
// original AST's type-decl's `Expr` (stripped of any&all `ParenExpr`s)
AstExpr ast.Expr
// a code-gen `TypeRef` to this `Type` decl's underlying-type
GenRef *udevgogen.TypeRef
}
// commonly useful code-gen values prepared for this `Type`
G struct {
// type-ref to this `Type`
T *udevgogen.TypeRef
// type-ref to pointer-to-`Type` (think 'ª for addr')
Tª *udevgogen.TypeRef
// type-ref to slice-of-`Type`
Ts *udevgogen.TypeRef
// type-ref to slice-of-pointers-to-`Type`
Tªs *udevgogen.TypeRef
// Name="this" and Type=.G.T
This udevgogen.NamedTyped
// Name="this" and Type=.G.Tª
Thisª udevgogen.NamedTyped
}
Enumish struct {
// expected to be builtin prim-type such as uint8, int64, int --- cases of additional indirections to be handled when they occur in practice
BaseType string
ConstNames []string
}
}
func (me *Type) IsArray() bool
func (me *Type) IsEnumish() bool
func (me *Type) IsSlice() bool
func (me *Type) IsSliceOrArray() bool
func (me *Type) SrcFileImportPathByName(impName string) *PkgSpec
type Types []*Type
func (me *Types) Add(t *Type)
func (me Types) Named(name string) *Type
type Variant struct {
Add bool
DocComment Str
Name string
}
Variant is like Variation
but auto-disabled unless Add
is set.
func (me *Variant) NameWith(placeholderNamesAndValues ...string) string
type Variation struct {
Disabled bool
DocComment Str
Name string
}
Variation is like Variant
but auto-enabled unless Disabled
is set.
func (me *Variation) NameWith(placeholderNamesAndValues ...string) string