Skip to content

Instantly share code, notes, and snippets.

@taichi
Last active October 26, 2018 14:50
Show Gist options
  • Save taichi/8130759 to your computer and use it in GitHub Desktop.
Save taichi/8130759 to your computer and use it in GitHub Desktop.
delegation code generator
package main
import (
"bytes"
"fmt"
"go/ast"
"go/build"
"go/format"
"go/parser"
"go/token"
"io"
"io/ioutil"
"path/filepath"
"strings"
)
func main() {
ctx := build.Default
loggerpath := filepath.Join(ctx.GOPATH, "src", "github.com/cihub/seelog", "logger.go")
fmt.Println(loggerpath)
err := process(loggerpath, "LoggerInterface", "logger")
if err != nil {
panic(err)
}
}
type context struct {
target, varname string
contents *[]byte
output io.Writer
}
type inspector struct {
ctx *context
}
func (i *inspector) Printf(format string, params ...interface{}) {
fmt.Fprintf(i.ctx.output, format, params...)
}
func (i *inspector) Visit(node ast.Node) (w ast.Visitor) {
if x, ok := node.(*ast.InterfaceType); ok {
for _, fl := range x.Methods.List {
name := fl.Names[0].Name
if first := name[0]; string(first) == strings.ToUpper(string(first)) {
i.Printf("func %s { ", (*i.ctx.contents)[fl.Pos()-1:fl.End()-1])
fn := fl.Type.(*ast.FuncType)
if fn.Results != nil {
i.Printf("return ")
}
i.Printf("%s.%s(", i.ctx.varname, name)
for index, p := range fn.Params.List {
if index != 0 {
i.Printf(", ")
}
i.Printf(p.Names[0].Name)
if _, isElip := p.Type.(*ast.Ellipsis); isElip {
i.Printf("...")
}
}
i.Printf(") }\n")
}
}
return nil
}
return i
}
type finder struct {
ctx *context
}
func (f *finder) Visit(node ast.Node) (w ast.Visitor) {
if x, ok := node.(*ast.TypeSpec); ok {
if x.Name.Name == f.ctx.target {
return &inspector{
ctx: f.ctx,
}
}
}
return f
}
func process(path, typename, varname string) error {
contents, errf := ioutil.ReadFile(path)
if errf != nil {
return errf
}
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, path, contents, 0)
if err != nil {
return err
}
var buffer bytes.Buffer
ast.Walk(&finder{
ctx: &context{
target: typename,
varname: varname,
contents: &contents,
output: &buffer,
},
}, f)
fmt.Fprintln(&buffer)
src, fmterr := format.Source(buffer.Bytes())
if fmterr != nil {
return fmterr
}
buffer.Reset()
buffer.Write(src)
fmt.Println(&buffer)
return nil
}
func Tracef(format string, params ...interface{}) { logger.Tracef(format, params...) }
func Debugf(format string, params ...interface{}) { logger.Debugf(format, params...) }
func Infof(format string, params ...interface{}) { logger.Infof(format, params...) }
func Warnf(format string, params ...interface{}) error { return logger.Warnf(format, params...) }
func Errorf(format string, params ...interface{}) error { return logger.Errorf(format, params...) }
func Criticalf(format string, params ...interface{}) error { return logger.Criticalf(format, params...) }
func Trace(v ...interface{}) { logger.Trace(v...) }
func Debug(v ...interface{}) { logger.Debug(v...) }
func Info(v ...interface{}) { logger.Info(v...) }
func Warn(v ...interface{}) error { return logger.Warn(v...) }
func Error(v ...interface{}) error { return logger.Error(v...) }
func Critical(v ...interface{}) error { return logger.Critical(v...) }
func Close() { logger.Close() }
func Flush() { logger.Flush() }
func Closed() bool { return logger.Closed() }
func SetAdditionalStackDepth(depth int) error { return logger.SetAdditionalStackDepth(depth) }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment