Skip to content

Code generation library for Go

License

Notifications You must be signed in to change notification settings

MyNihongo/codegen

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

38 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Basic sample

This is a code generator for Go.

package main

import (
	gen "github.com/MyNihongo/codegen"
	"fmt"
)

func main() {
	f := gen.NewFile("cool", "my-generator").Imports(
		gen.Import("fmt"),
		gen.ImportAlias("strings", "str"),
	)

	f.Func("main").Block(
		gen.Declare("val").Values(gen.QualFuncCall("str", "Title").Args(gen.String("hello, 世界!"))),
		gen.QualFuncCall("fmt", "Println").Args(gen.Identifier("val")),
	)

	if err := f.Save(`path to the file.go`); err != nil {
		fmt.Println(err)
	}
}

This code will produce the following output

// Code generated by my-generator. DO NOT EDIT.
package cool

import (
	"fmt"
	str "strings"
)

func main() {
	val := str.Title("hello, 世界!")
	fmt.Println(val)
}

Motivation

I have used Jennifer for code generation (don't get me wrong, the library is awesome 🚀), but I thought that its API is a bit too low-level.

With this library I aim to provide high-level functions with will resemble the actual Go code and will not require to write low-level statements.

  • gofmt is used for formatting
  • auto-generation comment is added automatically

Documentation

Identifiers

gen.Identifier("a")
// a

gen.Identifier("a").Pointer()
// *a

gen.Identifier("a").Address()
// &(a)

Useful identifier methods

gen.Identifier("a").Equals(gen.Identifier("b"))
// a == b

gen.Identifier("a").NotEquals(gen.Identifier("b"))
// a != b

gen.Err().IsNotNil()
// err != nil

gen.Err().IsNil()
// err == nil

gen.String("my string").IsNotEmpty()
// len("my string") != 0

Declare / assign variables

gen.Declare("val").Values(gen.String("my string"))
// val := "my string"

gen.Assign("val").Values(gen.String("my string"))
// val = "my string"

gen.Declare("val", "err").Values(FuncCall("myFunc").Args(Identifier("a")))
// val, err := myFunc(a)

gen.Assign("val", "err").Values(FuncCall("myFunc").Args(Identifier("a")))
// val, err = myFunc(a)

gen.DeclareVars(
	gen.Var("val", "string"),
	gen.QualVar("sb", "strings", "Builder"),
)
// var val string
// var sb strings.Builder

gen.Identifier("myVar").Assign(gen.Identifier("val"))
// myVar = val

Initialise structs

gen.InitStruct("myStruct").Props(
	gen.PropValue("prop", gen.String("string value")),
)
// myStruct{prop:"string value"}

gen.InitStruct("myStruct").Props(
	gen.PropValue("prop", gen.FuncCall("myFunc")),
).Address()
// &myStruct{prop:myFunc()}

Call functions

gen.FuncCall("myFunc")
// myFunc()

gen.FuncCall("myFunc").Args(
	gen.Identifier("a"),
	gen.FuncCall("anotherFunc"),
)
// myFunc(a, anotherFunc())

gen.QualFuncCall("fmt", "Println").Args(
	gen.String("string value")
)
// fmt.Println("string value")

Call go functions

gen.Len(Identifier("str"))
// len(str)

Defer functions

gen.Defer(gen.FuncCall("myFunc"))
// defer myFunc()

gen.Defer(gen.Identifier("a").Call("MyFunc"))
// defer a.MyFunc()

gen.Defer(gen.Lambda().Block(
	gen.Identifier("a").Call("MyFunc"),
).Call())
// defer func () {
//	a.MyFunc()
// }()
}

Access fields, call methods

gen.Identifier("a").
	Field("field").
	Call("myFunc").Args(String("str")).
	Field("field2")
// a.field.myFunc("str").field2

gen.FuncCall("myFunc").
	Call("anotherFunc").Args(Identifier("a")).
	Field("field")
// myFunc().anotherFunc(a).field

Pointers

gen.Identifier("a").Pointer().
	Field("field")
// (*a).field

gen.FuncCall("myFunc").Pointer().
	Field("field")
// (*myFunc()).field

Functions and methods

For methods the first argument is formatted according to Go conventions (first letter of the type in lowercase)

f := gen.NewFile("cool", "my-generator")
f.Func("myFunc")
// func myFunc() {}

f.Func("myFunc").
	Params(
		gen.Param("val", "string"),
		gen.QualParam("sb", "strings", "Builder").Pointer(),
	)
// func myFunc(val string, sb *strings.Builder) {
// }

f.Func("myFunc").ReturnTypes(
		gen.ReturnType("myType").Pointer(),
		gen.ReturnTypeError(),
	).Block(
		gen.Return(gen.Identifier("a"), gen.Nil()),
	)
// func myFunc() (*myType, error) {
//	return a, nil
// }

f.Func("myFunc").Block(
	gen.Return(),
)
// func myFunc() {
//	return
// }

Function API is available for methods as well

f := gen.NewFile("cool", "my-generator")
f.Method(
	gen.This("MyTypeName"),
	"coolMethod",
).ReturnTypes(
	gen.ReturnType("string"),
).Block(
	gen.Return(gen.Identifier("m").Field("field")),
)
// func (m MyTypeName) coolMethod() string {
//	return m.field
// }

If statements

If, else-if and else statements can be chained

gen.If(
	gen.Identifier("val").IsNotNil(),
).Block(
	gen.Return(Identifier("val")),
).Else(
	gen.Return(Nil()),
)
// if val != nil{
//	return val
// } else {
//	return nil
// }

gen.IfDecl(
	gen.Declare("val", "err").Values(gen.QualFuncCall("strconv", "Atoi").Args(gen.QualFuncCall("os", "Getenv").Args(gen.String("ENV_VAR")))),
	gen.Err().IsNil(),
).Block(
	gen.Identifier("config").Field("myVar").Assign(gen.Identifier("val")),
)
// if val, err := strconv.Atoi(os.Getenv("ENV_VAR")); err == nil {
//	config.myVar = val
// }

Structs and interfaces

f := gen.NewFile("cool", "my-generator")
f.Struct("myStruct").Props(
	gen.Property("name", "int").Pointer(),
)
// type myStruct struct {
//	name *int
// }

f.Interface("myInterface").Funcs(
	gen.FuncDecl("myFunc").Params(gen.Param("param", "int")).ReturnTypes(gen.ReturnType("string"))
)
// type myInterface interface {
//	myFunc(param int) string
// }

f.Type("myType", "int64")
// type myType int64

Utility methods

Generate a getter

f := gen.NewFile("cool", "my-generator").
f.GenerateGetter(gen.This("TypeName").Pointer(), "myField", gen.ReturnType("int"))
// func (t *TypeName) MyField() int {
//	return t.myField
// }