package main import ( "io" "strings" . "github.com/dave/jennifer/jen" ) func render(w io.Writer) error { file := NewFile("jen") file.HeaderComment("This file is generated - do not edit.") file.Line() for _, b := range groups { b := b // b used in closures comment := Commentf("%s %s", b.name, b.comment) if b.variadic && len(b.parameters) > 1 { panic("should not have variadic function with multiple params") } var variadic Code if b.variadic { variadic = Op("...") } var funcParams []Code var callParams []Code for _, name := range b.parameters { funcParams = append(funcParams, Id(name).Add(variadic).Id("Code")) callParams = append(callParams, Id(name).Add(variadic)) } addFunctionAndGroupMethod( file, b.name, comment, funcParams, callParams, false, ) /* // func (s *Statement) () *Statement { g := &Group{ items: []Code{}|, name: "", open: "", close: "", separator: "", multi: , } *s = append(*s, g) return s } */ file.Add(comment) file.Func().Params( Id("s").Op("*").Id("Statement"), ).Id(b.name).Params( funcParams..., ).Op("*").Id("Statement").Block( Id("g").Op(":=").Op("&").Id("Group").Values(Dict{ Id("items"): Do(func(s *Statement) { if b.variadic { s.Id(b.parameters[0]) } else { s.Index().Id("Code").ValuesFunc(func(g *Group) { for _, name := range b.parameters { g.Id(name) } }) } }), Id("name"): Lit(strings.ToLower(b.name)), Id("open"): Lit(b.opening), Id("close"): Lit(b.closing), Id("separator"): Lit(b.separator), Id("multi"): Lit(b.multi), }), Op("*").Id("s").Op("=").Append(Op("*").Id("s"), Id("g")), Return(Id("s")), ) if b.variadic && !b.preventFunc { funcName := b.name + "Func" funcComment := Commentf("%sFunc %s", b.name, b.comment) funcFuncParams := []Code{Id("f").Func().Params(Op("*").Id("Group"))} funcCallParams := []Code{Id("f")} addFunctionAndGroupMethod( file, funcName, funcComment, funcFuncParams, funcCallParams, false, ) /* // func (s *Statement) (f func(*Group)) *Statement { g := &Group{ name: "", open: "", close: "", separator: "", multi: , } f(g) *s = append(*s, g) return s } */ file.Add(funcComment) file.Func().Params( Id("s").Op("*").Id("Statement"), ).Id(funcName).Params( funcFuncParams..., ).Op("*").Id("Statement").Block( Id("g").Op(":=").Op("&").Id("Group").Values(Dict{ Id("name"): Lit(strings.ToLower(b.name)), Id("open"): Lit(b.opening), Id("close"): Lit(b.closing), Id("separator"): Lit(b.separator), Id("multi"): Lit(b.multi), }), Id("f").Call(Id("g")), Op("*").Id("s").Op("=").Append(Op("*").Id("s"), Id("g")), Return(Id("s")), ) } } type tkn struct { token string name string tokenType string tokenDesc string } tokens := []tkn{} for _, v := range identifiers { tokens = append(tokens, tkn{ token: v, name: strings.ToUpper(v[:1]) + v[1:], tokenType: "identifierToken", tokenDesc: "identifier", }) } for _, v := range keywords { tokens = append(tokens, tkn{ token: v, name: strings.ToUpper(v[:1]) + v[1:], tokenType: "keywordToken", tokenDesc: "keyword", }) } for i, t := range tokens { t := t // used in closures comment := Commentf( "%s renders the %s %s.", t.name, t.token, t.tokenDesc, ) addFunctionAndGroupMethod( file, t.name, comment, nil, nil, i != 0, // only enforce test coverage on one item ) /* // func (s *Statement) () *Statement { t := token{ typ: , content: "", } *s = append(*s, t) return s } */ file.Add(comment) file.Func().Params( Id("s").Op("*").Id("Statement"), ).Id(t.name).Params().Op("*").Id("Statement").Block( Do(func(s *Statement) { if i != 0 { // only enforce test coverage on one item s.Comment("notest") } }), Id("t").Op(":=").Id("token").Values(Dict{ Id("typ"): Id(t.tokenType), Id("content"): Lit(t.token), }), Op("*").Id("s").Op("=").Append(Op("*").Id("s"), Id("t")), Return(Id("s")), ) } return file.Render(w) } // For each method on *Statement, this generates a package level // function and a method on *Group, both with the same name. func addFunctionAndGroupMethod( file *File, name string, comment *Statement, funcParams []Code, callParams []Code, notest bool, ) { /* // func () *Statement { return newStatement().() } */ file.Add(comment) file.Func().Id(name).Params(funcParams...).Op("*").Id("Statement").Block( Do(func(s *Statement) { if notest { // only enforce test coverage on one item s.Comment("notest") } }), Return(Id("newStatement").Call().Dot(name).Call(callParams...)), ) /* // func (g *Group) () *Statement { s := () g.items = append(g.items, s) return s } */ file.Add(comment) file.Func().Params( Id("g").Op("*").Id("Group"), ).Id(name).Params(funcParams...).Op("*").Id("Statement").Block( Do(func(s *Statement) { if notest { // only enforce test coverage on one item s.Comment("notest") } }), Id("s").Op(":=").Id(name).Params(callParams...), Id("g").Dot("items").Op("=").Append(Id("g").Dot("items"), Id("s")), Return(Id("s")), ) }