package gen import ( "fmt" "sources.truenas.cloud/code/avo/internal/api" "sources.truenas.cloud/code/avo/internal/inst" "sources.truenas.cloud/code/avo/internal/prnt" "sources.truenas.cloud/code/avo/printer" ) type build struct { cfg printer.Config prnt.Generator } // NewBuild builds a printer that will generate instruction functions in the // build package. Each instruction will have one method on the build.Context // type, and a corresponding wrapper operating on the global Context. These // functions are thin wrappers around constructors generated by NewCtors. func NewBuild(cfg printer.Config) Interface { return GoFmt(&build{cfg: cfg}) } func (b *build) Generate(is []inst.Instruction) ([]byte, error) { b.Printf("// %s\n\n", b.cfg.GeneratedWarning()) b.Printf("package build\n\n") b.Printf("import (\n") b.Printf("\t%q\n", api.ImportPath(api.IRPackage)) b.Printf("\t%q\n", api.ImportPath(api.OperandPackage)) b.Printf("\t%q\n", api.ImportPath("x86")) b.Printf(")\n\n") // Helper to reduce source code size a little. b.Printf("func (c *Context) addinstruction(i *ir.Instruction, err error) {\n") b.Printf("if err == nil { c.Instruction(i) }") b.Printf(" else { c.adderror(err) }\n") b.Printf("}\n\n") // Generate build functions. fns := api.InstructionsFunctions(is) for _, fn := range fns { b.function(fn) } return b.Result() } func (b *build) function(fn *api.Function) { s := fn.Signature() d := fn.Doc() // Context method. methoddoc := append([]string{}, d...) methoddoc = append(methoddoc, fmt.Sprintf("Construct and append a %s instruction to the active function.", fn.Opcode())) b.Comment(methoddoc...) b.Printf("func (c *Context) %s(%s) {\n", fn.Name(), s.ParameterList()) b.Printf("c.addinstruction(x86.%s(%s))", fn.Name(), s.Arguments()) b.Printf("}\n\n") // Global version. globaldoc := append([]string{}, methoddoc...) globaldoc = append(globaldoc, "Operates on the global context.") b.Comment(globaldoc...) b.Printf("func %s(%s) { ctx.%s(%s) }\n\n", fn.Name(), s.ParameterList(), fn.Name(), s.Arguments()) }