commit 14fa9d63bddeff0c0ea1834428f4b78bfac227a5
parent a667dd76ca13c376331e6d9ec2d8746d085ff985
Author: francoispqt <francois@parquet.ninja>
Date: Sun, 3 Jun 2018 23:59:42 +0800
refactor generator code, add array
Diffstat:
17 files changed, 1215 insertions(+), 333 deletions(-)
diff --git a/gojay/gen.go b/gojay/gen.go
@@ -2,11 +2,9 @@ package main
import (
"go/ast"
- "html/template"
"log"
"os"
-
- "github.com/davecgh/go-spew/spew"
+ "text/template"
)
const genFileSuffix = "_gojay.go"
@@ -14,6 +12,19 @@ const genFileSuffix = "_gojay.go"
var pkgTpl *template.Template
var gojayImport = []byte("import \"github.com/francoispqt/gojay\"\n")
+type gen struct {
+ f *os.File
+ genTypes map[string]*ast.TypeSpec
+ vis *vis
+}
+
+type genTpl struct {
+ strTpl string
+ tpl *template.Template
+}
+
+type templateList map[string]*genTpl
+
func init() {
t, err := template.New("pkgDef").
Parse("package {{.PkgName}} \n\n")
@@ -23,59 +34,64 @@ func init() {
pkgTpl = t
}
-func (v *vis) gen() error {
- // open the file
- f, err := os.OpenFile(v.genFileName(), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0777)
+func parseTemplates(tpls templateList, pfx string) {
+ for k, t := range tpls {
+ tpl, err := template.New(pfx + k).Parse(t.strTpl)
+ if err != nil {
+ log.Fatal(err)
+ }
+ t.tpl = tpl
+ }
+}
+
+func (g *gen) writePkg(pkg string) error {
+ err := pkgTpl.Execute(g.f, struct {
+ PkgName string
+ }{
+ PkgName: pkg,
+ })
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (g *gen) writeGojayImport() error {
+ _, err := g.f.Write(gojayImport)
if err != nil {
return err
}
- defer f.Close()
+ return nil
+}
+
+func (g *gen) gen(pkg string) error {
// write package
- err = v.writePkg(f)
+ err := g.writePkg(pkg)
if err != nil {
return err
}
// write import of gojay
- err = v.writeGojayImport(f)
+ err = g.writeGojayImport()
if err != nil {
return err
}
// range over specs
// generate interfaces implementations based on type
- for _, s := range v.specs {
+ for _, s := range g.genTypes {
switch t := s.Type.(type) {
case *ast.StructType:
- err = v.genStruct(f, s.Name.String(), t)
+ err = g.genStruct(s.Name.String(), t)
if err != nil {
return err
}
case *ast.ArrayType:
- spew.Println(t, "arr")
+ err = g.genArray(s.Name.String(), t)
+ if err != nil {
+ return err
+ }
+ case *ast.MapType:
+ // TODO: generate for map type
}
}
return nil
}
-
-func (v *vis) genFileName() string {
- return v.file[:len(v.file)-3] + genFileSuffix
-}
-
-func (v *vis) writePkg(f *os.File) error {
- err := pkgTpl.Execute(f, struct {
- PkgName string
- }{
- PkgName: v.pkg,
- })
- if err != nil {
- return err
- }
- return nil
-}
-
-func (v *vis) writeGojayImport(f *os.File) error {
- _, err := f.Write(gojayImport)
- if err != nil {
- return err
- }
- return nil
-}
diff --git a/gojay/gen_array.go b/gojay/gen_array.go
@@ -0,0 +1,20 @@
+package main
+
+import (
+ "go/ast"
+)
+
+func (g *gen) genArray(n string, s *ast.ArrayType) error {
+ err := g.arrGenUnmarshal(n, s)
+ if err != nil {
+ return err
+ }
+
+ err = g.arrGenMarshal(n, s)
+ if err != nil {
+ return err
+ }
+ err = g.arrGenIsNil(n)
+
+ return nil
+}
diff --git a/gojay/gen_array_marshal.go b/gojay/gen_array_marshal.go
@@ -0,0 +1,220 @@
+package main
+
+import (
+ "errors"
+ "go/ast"
+)
+
+func init() {}
+
+func (g *gen) arrGenIsNil(n string) error {
+ err := arrMarshalTpl["isNil"].tpl.Execute(g.f, struct {
+ TypeName string
+ }{
+ TypeName: n,
+ })
+ return err
+}
+
+func (g *gen) arrGenMarshal(n string, s *ast.ArrayType) error {
+ err := arrMarshalTpl["def"].tpl.Execute(g.f, struct {
+ TypeName string
+ }{
+ TypeName: n,
+ })
+ if err != nil {
+ return err
+ }
+ // determine type of element in array
+ switch t := s.Elt.(type) {
+ case *ast.Ident:
+ err := g.arrGenMarshalIdent(t, false)
+ if err != nil {
+ return err
+ }
+ case *ast.StarExpr:
+ switch ptrExp := t.X.(type) {
+ case *ast.Ident:
+ err := g.arrGenMarshalIdent(ptrExp, true)
+ if err != nil {
+ return err
+ }
+ default:
+ return errors.New("Unknown type")
+ }
+ }
+ _, err = g.f.Write([]byte("}\n"))
+ if err != nil {
+ return err
+ }
+ return err
+}
+
+func (g *gen) arrGenMarshalIdent(i *ast.Ident, ptr bool) error {
+ switch i.String() {
+ case "string":
+ return g.arrMarshalString(ptr)
+ case "bool":
+ return g.arrMarshalBool(ptr)
+ case "int":
+ return g.arrMarshalInt("", ptr)
+ case "int64":
+ return g.arrMarshalInt("64", ptr)
+ case "int32":
+ return g.arrMarshalInt("32", ptr)
+ case "int16":
+ return g.arrMarshalInt("16", ptr)
+ case "int8":
+ return g.arrMarshalInt("8", ptr)
+ case "uint64":
+ return g.arrMarshalUint("64", ptr)
+ case "uint32":
+ return g.arrMarshalUint("32", ptr)
+ case "uint16":
+ return g.arrMarshalUint("16", ptr)
+ case "uint8":
+ return g.arrMarshalUint("8", ptr)
+ default:
+ // if ident is already in our spec list
+ if sp, ok := g.vis.specs[i.Name]; ok {
+ return g.arrMarshalNonPrim(sp, ptr)
+ } else if i.Obj != nil {
+ // else check the obj infos
+ switch t := i.Obj.Decl.(type) {
+ case *ast.TypeSpec:
+ return g.arrMarshalNonPrim(t, ptr)
+ default:
+ return errors.New("could not determine what to do with type " + i.String())
+ }
+ }
+ return errors.New("Unknown type")
+ }
+}
+
+func (g *gen) arrMarshalNonPrim(sp *ast.TypeSpec, ptr bool) error {
+ switch sp.Type.(type) {
+ case *ast.StructType:
+ return g.arrMarshalStruct(sp, ptr)
+ case *ast.ArrayType:
+ return g.arrMarshalArr(sp, ptr)
+ }
+ return nil
+}
+
+func (g *gen) arrMarshalString(ptr bool) error {
+ if ptr {
+ err := arrMarshalTpl["stringPtr"].tpl.Execute(g.f, struct {
+ Ptr string
+ }{""})
+ if err != nil {
+ return err
+ }
+ } else {
+ err := arrMarshalTpl["string"].tpl.Execute(g.f, struct {
+ Ptr string
+ }{"&"})
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (g *gen) arrMarshalBool(ptr bool) error {
+ if ptr {
+ err := arrMarshalTpl["bool"].tpl.Execute(g.f, struct {
+ Ptr string
+ }{""})
+ if err != nil {
+ return err
+ }
+ } else {
+ err := arrMarshalTpl["bool"].tpl.Execute(g.f, struct {
+ Ptr string
+ }{"&"})
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (g *gen) arrMarshalInt(intLen string, ptr bool) error {
+ if ptr {
+ err := arrMarshalTpl["int"].tpl.Execute(g.f, struct {
+ IntLen string
+ Ptr string
+ }{intLen, ""})
+ if err != nil {
+ return err
+ }
+ } else {
+ err := arrMarshalTpl["int"].tpl.Execute(g.f, struct {
+ IntLen string
+ Ptr string
+ }{intLen, "&"})
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (g *gen) arrMarshalUint(intLen string, ptr bool) error {
+ if ptr {
+ err := arrMarshalTpl["uint"].tpl.Execute(g.f, struct {
+ IntLen string
+ Ptr string
+ }{intLen, ""})
+ if err != nil {
+ return err
+ }
+ } else {
+ err := arrMarshalTpl["uint"].tpl.Execute(g.f, struct {
+ IntLen string
+ Ptr string
+ }{intLen, "&"})
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (g *gen) arrMarshalStruct(st *ast.TypeSpec, ptr bool) error {
+ if ptr {
+ err := arrMarshalTpl["structPtr"].tpl.Execute(g.f, struct {
+ StructName string
+ }{st.Name.String()})
+ if err != nil {
+ return err
+ }
+ } else {
+ err := arrMarshalTpl["struct"].tpl.Execute(g.f, struct {
+ StructName string
+ }{st.Name.String()})
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (g *gen) arrMarshalArr(st *ast.TypeSpec, ptr bool) error {
+ if ptr {
+ err := arrMarshalTpl["arrPtr"].tpl.Execute(g.f, struct {
+ StructName string
+ }{st.Name.String()})
+ if err != nil {
+ return err
+ }
+ } else {
+ err := arrMarshalTpl["arr"].tpl.Execute(g.f, struct {
+ StructName string
+ }{st.Name.String()})
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/gojay/gen_array_marshal_tpl.go b/gojay/gen_array_marshal_tpl.go
@@ -0,0 +1,58 @@
+package main
+
+var arrMarshalTpl = templateList{
+ "def": &genTpl{
+ strTpl: "\n// MarshalJSONArray implements gojay's MarshalerJSONArray" +
+ "\nfunc (v *{{.TypeName}}) MarshalJSONArray(enc *gojay.Encoder) {\n",
+ },
+ "isNil": &genTpl{
+ strTpl: "\n// IsNil implements gojay's MarshalerJSONArray" +
+ "\nfunc (v *{{.TypeName}}) IsNil() bool {\n" +
+ "\treturn *v == nil || len(*v) == 0\n" +
+ "}\n",
+ },
+ "string": &genTpl{
+ strTpl: "\tfor _, s := range *v {\n" +
+ "\t\tenc.String(s)\n" +
+ "\t}\n",
+ },
+ "bool": &genTpl{
+ strTpl: "\tfor _, s := range *v {\n" +
+ "\t\tenc.Bool(s)\n" +
+ "\t}\n",
+ },
+ "int": &genTpl{
+ strTpl: "\tfor _, s := range *v {\n" +
+ "\t\tenc.Int{{.IntLen}}(s)\n" +
+ "\t}\n",
+ },
+ "uint": &genTpl{
+ strTpl: "\tfor _, s := range *v {\n" +
+ "\t\tenc.Uint{{.IntLen}}(s)\n" +
+ "\t}\n",
+ },
+ "struct": &genTpl{
+ strTpl: "\tfor _, s := range *v {\n" +
+ "\t\tenc.Object(s)\n" +
+ "\t}\n",
+ },
+ "structPtr": &genTpl{
+ strTpl: "\tfor _, s := range *v {\n" +
+ "\t\tenc.Object(s)\n" +
+ "\t}\n",
+ },
+ "arr": &genTpl{
+ strTpl: "\tfor _, s := range *v {\n" +
+ "\t\tenc.Array(s)\n" +
+ "\t}\n",
+ },
+ "arrPtr": &genTpl{
+ strTpl: "\tfor _, s := range *v {\n" +
+ "\t\tenc.Array(s)\n" +
+ "\t}\n",
+ },
+}
+
+func init() {
+ parseTemplates(arrMarshalTpl, "arrMarshal")
+}
diff --git a/gojay/gen_array_unmarshal.go b/gojay/gen_array_unmarshal.go
@@ -0,0 +1,209 @@
+package main
+
+import (
+ "errors"
+ "go/ast"
+)
+
+func (g *gen) arrGenUnmarshal(n string, s *ast.ArrayType) error {
+ err := arrUnmarshalTpl["def"].tpl.Execute(g.f, struct {
+ TypeName string
+ }{
+ TypeName: n,
+ })
+ if err != nil {
+ return err
+ }
+ // determine type of element in array
+ switch t := s.Elt.(type) {
+ case *ast.Ident:
+ err := g.arrGenUnmarshalIdent(t, false)
+ if err != nil {
+ return err
+ }
+ case *ast.StarExpr:
+ switch ptrExp := t.X.(type) {
+ case *ast.Ident:
+ err := g.arrGenUnmarshalIdent(ptrExp, true)
+ if err != nil {
+ return err
+ }
+ default:
+ return errors.New("Unknown type")
+ }
+ }
+ _, err = g.f.Write(structUnmarshalClose)
+ if err != nil {
+ return err
+ }
+ return err
+}
+
+func (g *gen) arrGenUnmarshalIdent(i *ast.Ident, ptr bool) error {
+ switch i.String() {
+ case "string":
+ return g.arrUnmarshalString(ptr)
+ case "bool":
+ return g.arrUnmarshalBool(ptr)
+ case "int":
+ return g.arrUnmarshalInt("", ptr)
+ case "int64":
+ return g.arrUnmarshalInt("64", ptr)
+ case "int32":
+ return g.arrUnmarshalInt("32", ptr)
+ case "int16":
+ return g.arrUnmarshalInt("16", ptr)
+ case "int8":
+ return g.arrUnmarshalInt("8", ptr)
+ case "uint64":
+ return g.arrUnmarshalUint("64", ptr)
+ case "uint32":
+ return g.arrUnmarshalUint("32", ptr)
+ case "uint16":
+ return g.arrUnmarshalUint("16", ptr)
+ case "uint8":
+ return g.arrUnmarshalUint("8", ptr)
+ default:
+ // if ident is already in our spec list
+ if sp, ok := g.vis.specs[i.Name]; ok {
+ return g.arrUnmarshalNonPrim(sp, ptr)
+ } else if i.Obj != nil {
+ // else check the obj infos
+ switch t := i.Obj.Decl.(type) {
+ case *ast.TypeSpec:
+ return g.arrUnmarshalNonPrim(t, ptr)
+ default:
+ return errors.New("could not determine what to do with type " + i.String())
+ }
+ }
+ return errors.New("Unknown type")
+ }
+}
+
+func (g *gen) arrUnmarshalNonPrim(sp *ast.TypeSpec, ptr bool) error {
+ switch sp.Type.(type) {
+ case *ast.StructType:
+ return g.arrUnmarshalStruct(sp, ptr)
+ case *ast.ArrayType:
+ return g.arrUnmarshalArr(sp, ptr)
+ }
+ return nil
+}
+
+func (g *gen) arrUnmarshalString(ptr bool) error {
+ if ptr {
+ err := arrUnmarshalTpl["stringPtr"].tpl.Execute(g.f, struct {
+ Ptr string
+ }{""})
+ if err != nil {
+ return err
+ }
+ } else {
+ err := arrUnmarshalTpl["string"].tpl.Execute(g.f, struct {
+ Ptr string
+ }{"&"})
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (g *gen) arrUnmarshalBool(ptr bool) error {
+ if ptr {
+ err := arrUnmarshalTpl["bool"].tpl.Execute(g.f, struct {
+ Ptr string
+ }{""})
+ if err != nil {
+ return err
+ }
+ } else {
+ err := arrUnmarshalTpl["bool"].tpl.Execute(g.f, struct {
+ Ptr string
+ }{"&"})
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (g *gen) arrUnmarshalInt(intLen string, ptr bool) error {
+ if ptr {
+ err := arrUnmarshalTpl["int"].tpl.Execute(g.f, struct {
+ IntLen string
+ Ptr string
+ }{intLen, ""})
+ if err != nil {
+ return err
+ }
+ } else {
+ err := arrUnmarshalTpl["int"].tpl.Execute(g.f, struct {
+ IntLen string
+ Ptr string
+ }{intLen, "&"})
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (g *gen) arrUnmarshalUint(intLen string, ptr bool) error {
+ if ptr {
+ err := arrUnmarshalTpl["uint"].tpl.Execute(g.f, struct {
+ IntLen string
+ Ptr string
+ }{intLen, ""})
+ if err != nil {
+ return err
+ }
+ } else {
+ err := arrUnmarshalTpl["uint"].tpl.Execute(g.f, struct {
+ IntLen string
+ Ptr string
+ }{intLen, "&"})
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (g *gen) arrUnmarshalStruct(st *ast.TypeSpec, ptr bool) error {
+ if ptr {
+ err := arrUnmarshalTpl["structPtr"].tpl.Execute(g.f, struct {
+ StructName string
+ }{st.Name.String()})
+ if err != nil {
+ return err
+ }
+ } else {
+ err := arrUnmarshalTpl["struct"].tpl.Execute(g.f, struct {
+ StructName string
+ }{st.Name.String()})
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (g *gen) arrUnmarshalArr(st *ast.TypeSpec, ptr bool) error {
+ if ptr {
+ err := arrUnmarshalTpl["arrPtr"].tpl.Execute(g.f, struct {
+ StructName string
+ }{st.Name.String()})
+ if err != nil {
+ return err
+ }
+ } else {
+ err := arrUnmarshalTpl["arr"].tpl.Execute(g.f, struct {
+ StructName string
+ }{st.Name.String()})
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/gojay/gen_array_unmarshal_tpl.go b/gojay/gen_array_unmarshal_tpl.go
@@ -0,0 +1,64 @@
+package main
+
+var arrUnmarshalTpl = templateList{
+ "def": &genTpl{
+ strTpl: "\n// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray" +
+ "\nfunc (v *{{.TypeName}}) UnmarshalJSONArray(dec *gojay.Decoder) error {\n",
+ },
+ "string": &genTpl{
+ strTpl: "\tvar str string" +
+ "\n\tif err := dec.String(&str); err != nil {\n" +
+ "\t\treturn err\n\t}\n" +
+ "\t*v = append(*v, str)\n",
+ },
+ "stringPtr": &genTpl{
+ strTpl: "\n// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray" +
+ "\nfunc (v *{{.TypeName}}) UnmarshalJSONArray(dec *gojay.Decoder) error {\n",
+ },
+ "int": &genTpl{
+ strTpl: "\tvar i int{{.IntLen}}" +
+ "\n\tif err := dec.Int{{.IntLen}}(&i); err != nil {\n" +
+ "\t\treturn err\n\t}\n" +
+ "\t*v = append(*v, i)\n",
+ },
+ "uint": &genTpl{
+ strTpl: "\tvar i uint{{.IntLen}}" +
+ "\n\tif err := dec.Uint{{.IntLen}}(&i); err != nil {\n" +
+ "\t\treturn err\n\t}\n" +
+ "\t*v = append(*v, i)\n",
+ },
+ "bool": &genTpl{
+ strTpl: "\tvar b bool" +
+ "\n\tif err := dec.Bool(&b); err != nil {\n" +
+ "\t\treturn err\n\t}\n" +
+ "\t*v = append(*v, b)\n",
+ },
+ "struct": &genTpl{
+ strTpl: "\tvar s = {{.StructName}}{}" +
+ "\n\tif err := dec.Object(&s); err != nil {\n" +
+ "\t\treturn err\n\t}\n" +
+ "\t*v = append(*v, s)\n",
+ },
+ "structPtr": &genTpl{
+ strTpl: "\tvar s = &{{.StructName}}{}" +
+ "\n\tif err := dec.Object(s); err != nil {\n" +
+ "\t\treturn err\n\t}\n" +
+ "\t*v = append(*v, s)\n",
+ },
+ "arr": &genTpl{
+ strTpl: "\tvar s = make({{.StructName}}, 0)" +
+ "\n\tif err := dec.Array(&s); err != nil {\n" +
+ "\t\treturn err\n\t}\n" +
+ "\t*v = append(*v, s)\n",
+ },
+ "arrPtr": &genTpl{
+ strTpl: "\tvar s = make({{.StructName}}, 0)" +
+ "\n\tif err := dec.Array(&s); err != nil {\n" +
+ "\t\treturn err\n\t}\n" +
+ "\t*v = append(*v, &s)\n",
+ },
+}
+
+func init() {
+ parseTemplates(arrUnmarshalTpl, "arrUnarshal")
+}
diff --git a/gojay/gen_struct_marshal.go b/gojay/gen_struct_marshal.go
@@ -3,84 +3,11 @@ package main
import (
"errors"
"go/ast"
- "html/template"
- "log"
- "os"
- "reflect"
"strings"
-
- "github.com/davecgh/go-spew/spew"
)
-var structMarshalDefTpl *template.Template
-var structMarshalStringTpl *template.Template
-var structMarshalIntTpl *template.Template
-var structMarshalUintTpl *template.Template
-var structMarshalBoolTpl *template.Template
-var structMarshalStructTpl *template.Template
-
-var structIsNilTpl *template.Template
-
-var isNilMethod = `
-// IsNil returns wether the structure is nil value or not
-func (v *{{.StructName}}) IsNil() bool { return v == nil }
-`
-
-func init() {
- t, err := template.New("structUnmarshalDef").
- Parse("\n// MarshalJSONObject implements gojay's MarshalerJSONObject" +
- "\nfunc (v *{{.StructName}}) MarshalJSONObject(enc *gojay.Encoder) {\n",
- )
- if err != nil {
- log.Fatal(err)
- }
- structMarshalDefTpl = t
-
- t, err = template.New("structMarshalCaseString").
- Parse("\tenc.StringKey(\"{{.Key}}\", v.{{.Field}})\n")
- if err != nil {
- log.Fatal(err)
- }
- structMarshalStringTpl = t
-
- t, err = template.New("structMarshalCaseInt").
- Parse("\tenc.Int{{.IntLen}}Key(\"{{.Key}}\", v.{{.Field}})\n")
- if err != nil {
- log.Fatal(err)
- }
- structMarshalIntTpl = t
-
- t, err = template.New("structMarshalCaseUint").
- Parse("\tenc.Uint{{.IntLen}}Key(\"{{.Key}}\", v.{{.Field}})\n")
- if err != nil {
- log.Fatal(err)
- }
- structMarshalUintTpl = t
-
- t, err = template.New("structMarshalCaseBool").
- Parse("\tenc.BoolKey(\"{{.Key}}\", v.{{.Field}})\n")
- if err != nil {
- log.Fatal(err)
- }
- structMarshalBoolTpl = t
-
- t, err = template.New("structMarshalCaseStruct").
- Parse("\tenc.ObjectKey(\"{{.Key}}\", v.{{.Field}})\n")
- if err != nil {
- log.Fatal(err)
- }
- structMarshalStructTpl = t
-
- t, err = template.New("structMarhalIsNil").
- Parse(isNilMethod)
- if err != nil {
- log.Fatal(err)
- }
- structIsNilTpl = t
-}
-
-func (v *vis) structGenIsNil(f *os.File, n string) error {
- err := structIsNilTpl.Execute(f, struct {
+func (g *gen) structGenIsNil(n string) error {
+ err := structMarshalTpl["isNil"].tpl.Execute(g.f, struct {
StructName string
}{
StructName: n,
@@ -88,8 +15,8 @@ func (v *vis) structGenIsNil(f *os.File, n string) error {
return err
}
-func (v *vis) structGenMarshalObj(f *os.File, n string, s *ast.StructType) (int, error) {
- err := structMarshalDefTpl.Execute(f, struct {
+func (g *gen) structGenMarshalObj(n string, s *ast.StructType) (int, error) {
+ err := structMarshalTpl["def"].tpl.Execute(g.f, struct {
StructName string
}{
StructName: n,
@@ -104,7 +31,7 @@ func (v *vis) structGenMarshalObj(f *os.File, n string, s *ast.StructType) (int,
switch t := field.Type.(type) {
case *ast.Ident:
var err error
- keys, err = v.structGenMarshalIdent(f, field, t, keys)
+ keys, err = g.structGenMarshalIdent(field, t, keys, false)
if err != nil {
return 0, err
}
@@ -112,165 +39,225 @@ func (v *vis) structGenMarshalObj(f *os.File, n string, s *ast.StructType) (int,
switch ptrExp := t.X.(type) {
case *ast.Ident:
var err error
- keys, err = v.structGenMarshalIdent(f, field, ptrExp, keys)
+ keys, err = g.structGenMarshalIdent(field, ptrExp, keys, true)
if err != nil {
return 0, err
}
default:
- spew.Println(reflect.TypeOf(ptrExp))
- spew.Println(ptrExp)
+ return 0, errors.New("Unknown type")
}
- default:
- spew.Println(t)
}
}
}
- _, err = f.Write([]byte("}\n"))
+ _, err = g.f.Write([]byte("}\n"))
if err != nil {
return 0, err
}
return keys, nil
}
-func (v *vis) structGenMarshalIdent(f *os.File, field *ast.Field, i *ast.Ident, keys int) (int, error) {
+func (g *gen) structGenMarshalIdent(field *ast.Field, i *ast.Ident, keys int, ptr bool) (int, error) {
switch i.String() {
case "string":
- var err = v.structMarshalString(f, field)
+ var err = g.structMarshalString(field, ptr)
if err != nil {
return 0, err
}
keys++
case "bool":
- var err = v.structMarshalBool(f, field)
+ var err = g.structMarshalBool(field, ptr)
if err != nil {
return 0, err
}
keys++
case "int":
- var err = v.structMarshalInt(f, field, "")
+ var err = g.structMarshalInt(field, "", ptr)
if err != nil {
return 0, err
}
keys++
case "int64":
- var err = v.structMarshalInt(f, field, "64")
+ var err = g.structMarshalInt(field, "64", ptr)
if err != nil {
return 0, err
}
keys++
case "int32":
- var err = v.structMarshalInt(f, field, "32")
+ var err = g.structMarshalInt(field, "32", ptr)
if err != nil {
return 0, err
}
keys++
case "int16":
- var err = v.structMarshalInt(f, field, "16")
+ var err = g.structMarshalInt(field, "16", ptr)
if err != nil {
return 0, err
}
keys++
case "int8":
- var err = v.structMarshalInt(f, field, "8")
+ var err = g.structMarshalInt(field, "8", ptr)
if err != nil {
return 0, err
}
keys++
case "uint64":
- var err = v.structMarshalUint(f, field, "64")
+ var err = g.structMarshalUint(field, "64", ptr)
if err != nil {
return 0, err
}
keys++
case "uint32":
- var err = v.structMarshalUint(f, field, "32")
+ var err = g.structMarshalUint(field, "32", ptr)
if err != nil {
return 0, err
}
keys++
case "uint16":
- var err = v.structMarshalUint(f, field, "16")
+ var err = g.structMarshalUint(field, "16", ptr)
if err != nil {
return 0, err
}
keys++
case "uint8":
- var err = v.structMarshalUint(f, field, "8")
+ var err = g.structMarshalUint(field, "8", ptr)
if err != nil {
return 0, err
}
keys++
default:
- switch t := i.Obj.Decl.(type) {
- case *ast.TypeSpec:
- var err = v.structMarshalStruct(f, field, t)
+ // if ident is already in our spec list
+ if sp, ok := g.vis.specs[i.Name]; ok {
+ err := g.structMarshalNonPrim(field, sp, ptr)
if err != nil {
return 0, err
}
keys++
- default:
- return 0, errors.New("could not determine what to do with type " + i.String())
+ } else if i.Obj != nil {
+ switch t := i.Obj.Decl.(type) {
+ case *ast.TypeSpec:
+ var err = g.structMarshalNonPrim(field, t, ptr)
+ if err != nil {
+ return 0, err
+ }
+ keys++
+ default:
+ return 0, errors.New("could not determine what to do with type " + i.String())
+ }
+ } else {
+ return 0, errors.New("Unknown type")
}
}
return keys, nil
}
-func (v *vis) structMarshalString(f *os.File, field *ast.Field) error {
+func (g *gen) structMarshalNonPrim(field *ast.Field, sp *ast.TypeSpec, ptr bool) error {
+ switch sp.Type.(type) {
+ case *ast.StructType:
+ return g.structMarshalStruct(field, sp, ptr)
+ case *ast.ArrayType:
+ return g.structMarshalArr(field, sp, ptr)
+ }
+ return nil
+}
+
+func (g *gen) structMarshalString(field *ast.Field, ptr bool) error {
key := field.Names[0].String()
- err := structMarshalStringTpl.Execute(f, struct {
+ ptrStr := ""
+ if ptr {
+ ptrStr = "*"
+ }
+ err := structMarshalTpl["string"].tpl.Execute(g.f, struct {
Field string
Key string
- }{key, strings.ToLower(key)})
+ Ptr string
+ }{key, strings.ToLower(key), ptrStr})
if err != nil {
return err
}
return nil
}
-func (v *vis) structMarshalBool(f *os.File, field *ast.Field) error {
+func (g *gen) structMarshalBool(field *ast.Field, ptr bool) error {
key := field.Names[0].String()
- err := structMarshalBoolTpl.Execute(f, struct {
+ ptrStr := ""
+ if ptr {
+ ptrStr = "*"
+ }
+ err := structMarshalTpl["bool"].tpl.Execute(g.f, struct {
Field string
Key string
- }{key, strings.ToLower(key)})
+ Ptr string
+ }{key, strings.ToLower(key), ptrStr})
if err != nil {
return err
}
return nil
}
-func (v *vis) structMarshalInt(f *os.File, field *ast.Field, intLen string) error {
+func (g *gen) structMarshalInt(field *ast.Field, intLen string, ptr bool) error {
key := field.Names[0].String()
- err := structMarshalIntTpl.Execute(f, struct {
+ ptrStr := ""
+ if ptr {
+ ptrStr = "*"
+ }
+ err := structMarshalTpl["int"].tpl.Execute(g.f, struct {
Field string
IntLen string
Key string
- }{key, intLen, strings.ToLower(key)})
+ Ptr string
+ }{key, intLen, strings.ToLower(key), ptrStr})
if err != nil {
return err
}
return nil
}
-func (v *vis) structMarshalUint(f *os.File, field *ast.Field, intLen string) error {
+func (g *gen) structMarshalUint(field *ast.Field, intLen string, ptr bool) error {
key := field.Names[0].String()
- err := structMarshalUintTpl.Execute(f, struct {
+ ptrStr := ""
+ if ptr {
+ ptrStr = "*"
+ }
+ err := structMarshalTpl["uint"].tpl.Execute(g.f, struct {
Field string
IntLen string
Key string
- }{key, intLen, strings.ToLower(key)})
+ Ptr string
+ }{key, intLen, strings.ToLower(key), ptrStr})
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (g *gen) structMarshalStruct(field *ast.Field, st *ast.TypeSpec, ptr bool) error {
+ key := field.Names[0].String()
+ ptrStr := ""
+ if ptr {
+ ptrStr = "*"
+ }
+ var err = structMarshalTpl["struct"].tpl.Execute(g.f, struct {
+ Key string
+ Field string
+ Ptr string
+ }{strings.ToLower(key), key, ptrStr})
if err != nil {
return err
}
return nil
}
-func (v *vis) structMarshalStruct(f *os.File, field *ast.Field, st *ast.TypeSpec) error {
+func (g *gen) structMarshalArr(field *ast.Field, st *ast.TypeSpec, ptr bool) error {
key := field.Names[0].String()
- var err = structMarshalStructTpl.Execute(f, struct {
+ ptrStr := ""
+ if ptr {
+ ptrStr = "*"
+ }
+ var err = structMarshalTpl["arr"].tpl.Execute(g.f, struct {
Key string
Field string
- }{strings.ToLower(key), key})
+ Ptr string
+ }{strings.ToLower(key), key, ptrStr})
if err != nil {
return err
}
diff --git a/gojay/gen_struct_marshal_tpl.go b/gojay/gen_struct_marshal_tpl.go
@@ -0,0 +1,36 @@
+package main
+
+var structMarshalTpl = templateList{
+ "def": &genTpl{
+ strTpl: "\n// MarshalJSONObject implements gojay's MarshalerJSONObject" +
+ "\nfunc (v *{{.StructName}}) MarshalJSONObject(enc *gojay.Encoder) {\n",
+ },
+ "isNil": &genTpl{
+ strTpl: `
+// IsNil returns wether the structure is nil value or not
+func (v *{{.StructName}}) IsNil() bool { return v == nil }
+`,
+ },
+ "string": &genTpl{
+ strTpl: "\tenc.StringKey(\"{{.Key}}\", {{.Ptr}}v.{{.Field}})\n",
+ },
+ "int": &genTpl{
+ strTpl: "\tenc.Int{{.IntLen}}Key(\"{{.Key}}\", {{.Ptr}}v.{{.Field}})\n",
+ },
+ "uint": &genTpl{
+ strTpl: "\tenc.Uint{{.IntLen}}Key(\"{{.Key}}\", {{.Ptr}}v.{{.Field}})\n",
+ },
+ "bool": &genTpl{
+ strTpl: "\tenc.BoolKey(\"{{.Key}}\", {{.Ptr}}v.{{.Field}})\n",
+ },
+ "struct": &genTpl{
+ strTpl: "\tenc.ObjectKey(\"{{.Key}}\", v.{{.Field}})\n",
+ },
+ "arr": &genTpl{
+ strTpl: "\tenc.ArrayKey(\"{{.Key}}\", v.{{.Field}})\n",
+ },
+}
+
+func init() {
+ parseTemplates(structMarshalTpl, "structMarshal")
+}
diff --git a/gojay/gen_struct_unmarshal.go b/gojay/gen_struct_unmarshal.go
@@ -3,101 +3,14 @@ package main
import (
"errors"
"go/ast"
- "html/template"
- "log"
- "os"
- "reflect"
"strings"
-
- "github.com/davecgh/go-spew/spew"
)
-var structUnmarshalDefTpl *template.Template
-var structUnmarshalCaseTpl *template.Template
-var structUnmarshalStringTpl *template.Template
-var structUnmarshalIntTpl *template.Template
-var structUnmarshalUintTpl *template.Template
-var structUnmarshalBoolTpl *template.Template
-var structUnmarshalStructTpl *template.Template
-
-var structNKeysTpl *template.Template
-
-var nKeysMethod = `
-// NKeys returns the number of keys to unmarshal
-func (v *{{.StructName}}) NKeys() int { return {{.NKeys}} }
-`
-
var structUnmarshalSwitchOpen = []byte("\tswitch k {\n")
var structUnmarshalClose = []byte("\treturn nil\n}\n")
-func init() {
- t, err := template.New("structUnmarshalDef").
- Parse("\n// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject" +
- "\nfunc (v *{{.StructName}}) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {\n",
- )
- if err != nil {
- log.Fatal(err)
- }
- structUnmarshalDefTpl = t
-
- t, err = template.New("structUnmarshalCase").
- Parse("\tcase \"{{.Key}}\":\n")
- if err != nil {
- log.Fatal(err)
- }
- structUnmarshalCaseTpl = t
-
- t, err = template.New("structUnmarshalCaseString").
- Parse("\t\treturn dec.String(&v.{{.Field}})\n")
- if err != nil {
- log.Fatal(err)
- }
- structUnmarshalStringTpl = t
-
- t, err = template.New("structUnmarshalCaseInt").
- Parse("\t\treturn dec.Int{{.IntLen}}(&v.{{.Field}})\n")
- if err != nil {
- log.Fatal(err)
- }
- structUnmarshalIntTpl = t
-
- t, err = template.New("structUnmarshalCaseUint").
- Parse("\t\treturn dec.Uint{{.IntLen}}(&v.{{.Field}})\n")
- if err != nil {
- log.Fatal(err)
- }
- structUnmarshalUintTpl = t
-
- t, err = template.New("structUnmarshalCaseBool").
- Parse("\t\treturn dec.Bool(&v.{{.Field}})\n")
- if err != nil {
- log.Fatal(err)
- }
- structUnmarshalBoolTpl = t
-
- t, err = template.New("structUnmarshalCaseStruct").
- Parse(
- ` if v.{{.Field}} == nil {
- v.{{.Field}} = &{{.StructName}}{}
- }
- dec.Object(v.{{.Field}})
-`)
- if err != nil {
- log.Fatal(err)
- }
- structUnmarshalStructTpl = t
-
- t, err = template.New("structUnmarshalNKeys").
- Parse(nKeysMethod)
- if err != nil {
- log.Fatal(err)
- }
- structNKeysTpl = t
-
-}
-
-func (v *vis) structGenNKeys(f *os.File, n string, count int) error {
- err := structNKeysTpl.Execute(f, struct {
+func (g *gen) structGenNKeys(n string, count int) error {
+ err := structUnmarshalTpl["nKeys"].tpl.Execute(g.f, struct {
NKeys int
StructName string
}{
@@ -107,8 +20,8 @@ func (v *vis) structGenNKeys(f *os.File, n string, count int) error {
return err
}
-func (v *vis) structGenUnmarshalObj(f *os.File, n string, s *ast.StructType) (int, error) {
- err := structUnmarshalDefTpl.Execute(f, struct {
+func (g *gen) structGenUnmarshalObj(n string, s *ast.StructType) (int, error) {
+ err := structUnmarshalTpl["def"].tpl.Execute(g.f, struct {
StructName string
}{
StructName: n,
@@ -119,14 +32,14 @@ func (v *vis) structGenUnmarshalObj(f *os.File, n string, s *ast.StructType) (in
keys := 0
if len(s.Fields.List) > 0 {
// open switch statement
- f.Write(structUnmarshalSwitchOpen)
+ g.f.Write(structUnmarshalSwitchOpen)
// TODO: check tags
for _, field := range s.Fields.List {
switch t := field.Type.(type) {
case *ast.Ident:
var err error
- keys, err = v.structGenUnmarshalIdent(f, field, t, keys)
+ keys, err = g.structGenUnmarshalIdent(field, t, keys, false)
if err != nil {
return 0, err
}
@@ -134,192 +47,285 @@ func (v *vis) structGenUnmarshalObj(f *os.File, n string, s *ast.StructType) (in
switch ptrExp := t.X.(type) {
case *ast.Ident:
var err error
- keys, err = v.structGenUnmarshalIdent(f, field, ptrExp, keys)
+ keys, err = g.structGenUnmarshalIdent(field, ptrExp, keys, true)
if err != nil {
return 0, err
}
default:
- spew.Println(reflect.TypeOf(ptrExp))
- spew.Println(ptrExp)
+ return 0, errors.New("Unknown type1")
}
- default:
- spew.Println(t)
}
}
// close switch statement
- f.Write([]byte("\t}\n"))
+ g.f.Write([]byte("\t}\n"))
}
- _, err = f.Write(structUnmarshalClose)
+ _, err = g.f.Write(structUnmarshalClose)
if err != nil {
return 0, err
}
return keys, nil
}
-func (v *vis) structGenUnmarshalIdent(f *os.File, field *ast.Field, i *ast.Ident, keys int) (int, error) {
+func (g *gen) structGenUnmarshalIdent(field *ast.Field, i *ast.Ident, keys int, ptr bool) (int, error) {
switch i.String() {
case "string":
- var err = v.structUnmarshalString(f, field)
+ var err = g.structUnmarshalString(field, ptr)
if err != nil {
return 0, err
}
keys++
case "bool":
- var err = v.structUnmarshalBool(f, field)
+ var err = g.structUnmarshalBool(field, ptr)
if err != nil {
return 0, err
}
keys++
case "int":
- var err = v.structUnmarshalInt(f, field, "")
+ var err = g.structUnmarshalInt(field, "", ptr)
if err != nil {
return 0, err
}
keys++
case "int64":
- var err = v.structUnmarshalInt(f, field, "64")
+ var err = g.structUnmarshalInt(field, "64", ptr)
if err != nil {
return 0, err
}
keys++
case "int32":
- var err = v.structUnmarshalInt(f, field, "32")
+ var err = g.structUnmarshalInt(field, "32", ptr)
if err != nil {
return 0, err
}
keys++
case "int16":
- var err = v.structUnmarshalInt(f, field, "16")
+ var err = g.structUnmarshalInt(field, "16", ptr)
if err != nil {
return 0, err
}
keys++
case "int8":
- var err = v.structUnmarshalInt(f, field, "8")
+ var err = g.structUnmarshalInt(field, "8", ptr)
if err != nil {
return 0, err
}
keys++
case "uint64":
- var err = v.structUnmarshalUint(f, field, "64")
+ var err = g.structUnmarshalUint(field, "64", ptr)
if err != nil {
return 0, err
}
keys++
case "uint32":
- var err = v.structUnmarshalUint(f, field, "32")
+ var err = g.structUnmarshalUint(field, "32", ptr)
if err != nil {
return 0, err
}
keys++
case "uint16":
- var err = v.structUnmarshalUint(f, field, "16")
+ var err = g.structUnmarshalUint(field, "16", ptr)
if err != nil {
return 0, err
}
keys++
case "uint8":
- var err = v.structUnmarshalUint(f, field, "8")
+ var err = g.structUnmarshalUint(field, "8", ptr)
if err != nil {
return 0, err
}
keys++
default:
- switch t := i.Obj.Decl.(type) {
- case *ast.TypeSpec:
- var err = v.structUnmarshalStruct(f, field, t)
+ // if ident is already in our spec list
+ if sp, ok := g.vis.specs[i.Name]; ok {
+ err := g.structUnmarshalNonPrim(field, sp, ptr)
if err != nil {
return 0, err
}
keys++
- default:
- return 0, errors.New("could not determine what to do with type " + i.String())
+ } else if i.Obj != nil {
+ // else check the obj infos
+ switch t := i.Obj.Decl.(type) {
+ case *ast.TypeSpec:
+ err := g.structUnmarshalNonPrim(field, t, ptr)
+ if err != nil {
+ return 0, err
+ }
+ keys++
+ default:
+ return 0, errors.New("could not determine what to do with type " + i.String())
+ }
+ } else {
+ return 0, errors.New("Unknown type")
}
}
return keys, nil
}
-func (v *vis) structUnmarshalString(f *os.File, field *ast.Field) error {
+func (g *gen) structUnmarshalNonPrim(field *ast.Field, sp *ast.TypeSpec, ptr bool) error {
+ switch sp.Type.(type) {
+ case *ast.StructType:
+ return g.structUnmarshalStruct(field, sp, ptr)
+ case *ast.ArrayType:
+ return g.structUnmarshalArr(field, sp, ptr)
+ }
+ return errors.New("Unknown type")
+}
+
+func (g *gen) structUnmarshalString(field *ast.Field, ptr bool) error {
key := field.Names[0].String()
- err := structUnmarshalCaseTpl.Execute(f, struct {
+ err := structUnmarshalTpl["case"].tpl.Execute(g.f, struct {
Key string
}{strings.ToLower(key)})
if err != nil {
return err
}
- err = structUnmarshalStringTpl.Execute(f, struct {
- Field string
- }{key})
- if err != nil {
- return err
+ if ptr {
+ err = structUnmarshalTpl["string"].tpl.Execute(g.f, struct {
+ Field string
+ Ptr string
+ }{key, ""})
+ if err != nil {
+ return err
+ }
+ } else {
+ err = structUnmarshalTpl["string"].tpl.Execute(g.f, struct {
+ Field string
+ Ptr string
+ }{key, "&"})
+ if err != nil {
+ return err
+ }
}
return nil
}
-func (v *vis) structUnmarshalBool(f *os.File, field *ast.Field) error {
+func (g *gen) structUnmarshalBool(field *ast.Field, ptr bool) error {
key := field.Names[0].String()
- err := structUnmarshalCaseTpl.Execute(f, struct {
+ err := structUnmarshalTpl["case"].tpl.Execute(g.f, struct {
Key string
}{strings.ToLower(key)})
if err != nil {
return err
}
- err = structUnmarshalBoolTpl.Execute(f, struct {
- Field string
- }{key})
- if err != nil {
- return err
+ if ptr {
+ err = structUnmarshalTpl["bool"].tpl.Execute(g.f, struct {
+ Field string
+ Ptr string
+ }{key, ""})
+ if err != nil {
+ return err
+ }
+ } else {
+ err = structUnmarshalTpl["bool"].tpl.Execute(g.f, struct {
+ Field string
+ Ptr string
+ }{key, "&"})
+ if err != nil {
+ return err
+ }
}
return nil
}
-func (v *vis) structUnmarshalInt(f *os.File, field *ast.Field, intLen string) error {
+func (g *gen) structUnmarshalInt(field *ast.Field, intLen string, ptr bool) error {
key := field.Names[0].String()
- err := structUnmarshalCaseTpl.Execute(f, struct {
+ err := structUnmarshalTpl["case"].tpl.Execute(g.f, struct {
Key string
}{strings.ToLower(key)})
if err != nil {
return err
}
- err = structUnmarshalIntTpl.Execute(f, struct {
- Field string
- IntLen string
- }{key, intLen})
- if err != nil {
- return err
+ if ptr {
+ err = structUnmarshalTpl["int"].tpl.Execute(g.f, struct {
+ Field string
+ IntLen string
+ Ptr string
+ }{key, intLen, ""})
+ if err != nil {
+ return err
+ }
+ } else {
+ err = structUnmarshalTpl["int"].tpl.Execute(g.f, struct {
+ Field string
+ IntLen string
+ Ptr string
+ }{key, intLen, "&"})
+ if err != nil {
+ return err
+ }
}
return nil
}
-func (v *vis) structUnmarshalUint(f *os.File, field *ast.Field, intLen string) error {
+func (g *gen) structUnmarshalUint(field *ast.Field, intLen string, ptr bool) error {
key := field.Names[0].String()
- err := structUnmarshalCaseTpl.Execute(f, struct {
+ err := structUnmarshalTpl["case"].tpl.Execute(g.f, struct {
Key string
}{strings.ToLower(key)})
if err != nil {
return err
}
- err = structUnmarshalUintTpl.Execute(f, struct {
- Field string
- IntLen string
- }{key, intLen})
+ if ptr {
+ err = structUnmarshalTpl["uint"].tpl.Execute(g.f, struct {
+ Field string
+ IntLen string
+ Ptr string
+ }{key, intLen, ""})
+ if err != nil {
+ return err
+ }
+ } else {
+ err = structUnmarshalTpl["uint"].tpl.Execute(g.f, struct {
+ Field string
+ IntLen string
+ Ptr string
+ }{key, intLen, "&"})
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (g *gen) structUnmarshalStruct(field *ast.Field, st *ast.TypeSpec, ptr bool) error {
+ key := field.Names[0].String()
+ err := structUnmarshalTpl["case"].tpl.Execute(g.f, struct {
+ Key string
+ }{strings.ToLower(key)})
if err != nil {
return err
}
+ if ptr {
+ err = structUnmarshalTpl["struct"].tpl.Execute(g.f, struct {
+ Field string
+ StructName string
+ }{key, st.Name.String()})
+ if err != nil {
+ return err
+ }
+ } else {
+ err = structUnmarshalTpl["struct"].tpl.Execute(g.f, struct {
+ Field string
+ StructName string
+ }{key, st.Name.String()})
+ if err != nil {
+ return err
+ }
+ }
return nil
}
-func (v *vis) structUnmarshalStruct(f *os.File, field *ast.Field, st *ast.TypeSpec) error {
+func (g *gen) structUnmarshalArr(field *ast.Field, st *ast.TypeSpec, ptr bool) error {
key := field.Names[0].String()
- err := structUnmarshalCaseTpl.Execute(f, struct {
+ err := structUnmarshalTpl["case"].tpl.Execute(g.f, struct {
Key string
}{strings.ToLower(key)})
if err != nil {
return err
}
- err = structUnmarshalStructTpl.Execute(f, struct {
- Field string
- StructName string
+ err = structUnmarshalTpl["arr"].tpl.Execute(g.f, struct {
+ Field string
+ TypeName string
}{key, st.Name.String()})
if err != nil {
return err
diff --git a/gojay/gen_struct_unmarshal_tpl.go b/gojay/gen_struct_unmarshal_tpl.go
@@ -0,0 +1,48 @@
+package main
+
+var structUnmarshalTpl = templateList{
+ "def": &genTpl{
+ strTpl: "\n// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject" +
+ "\nfunc (v *{{.StructName}}) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {\n",
+ },
+ "nKeys": &genTpl{
+ strTpl: `
+// NKeys returns the number of keys to unmarshal
+func (v *{{.StructName}}) NKeys() int { return {{.NKeys}} }
+`,
+ },
+ "case": &genTpl{
+ strTpl: "\tcase \"{{.Key}}\":\n",
+ },
+ "string": &genTpl{
+ strTpl: "\t\treturn dec.String({{.Ptr}}v.{{.Field}})\n",
+ },
+ "int": &genTpl{
+ strTpl: "\t\treturn dec.Int{{.IntLen}}({{.Ptr}}v.{{.Field}})\n",
+ },
+ "uint": &genTpl{
+ strTpl: "\t\treturn dec.Uint{{.IntLen}}({{.Ptr}}v.{{.Field}})\n",
+ },
+ "bool": &genTpl{
+ strTpl: "\t\treturn dec.Bool({{.Ptr}}v.{{.Field}})\n",
+ },
+ "struct": &genTpl{
+ strTpl: ` if v.{{.Field}} == nil {
+ v.{{.Field}} = &{{.StructName}}{}
+ }
+ dec.Object(v.{{.Field}})
+`,
+ },
+ "arr": &genTpl{
+ strTpl: ` if v.{{.Field}} == nil {
+ arr := make({{.TypeName}}, 0)
+ v.{{.Field}} = &arr
+ }
+ dec.Array(v.{{.Field}})
+`,
+ },
+}
+
+func init() {
+ parseTemplates(structUnmarshalTpl, "structUnmarshal")
+}
diff --git a/gojay/gen_stuct.go b/gojay/gen_stuct.go
@@ -2,20 +2,19 @@ package main
import (
"go/ast"
- "os"
)
-func (v *vis) genStruct(f *os.File, n string, s *ast.StructType) error {
- keys, err := v.structGenUnmarshalObj(f, n, s)
+func (g *gen) genStruct(n string, s *ast.StructType) error {
+ keys, err := g.structGenUnmarshalObj(n, s)
if err != nil {
return err
}
- err = v.structGenNKeys(f, n, keys)
+ err = g.structGenNKeys(n, keys)
- keys, err = v.structGenMarshalObj(f, n, s)
+ keys, err = g.structGenMarshalObj(n, s)
if err != nil {
return err
}
- err = v.structGenIsNil(f, n)
+ err = g.structGenIsNil(n)
return nil
}
diff --git a/gojay/main.go b/gojay/main.go
@@ -50,18 +50,25 @@ func getFiles() ([]string, error) {
}
func main() {
- files, err := getFiles()
+ p, err := getPath()
if err != nil {
log.Fatal(err)
}
- for _, f := range files {
- fset := token.NewFileSet()
- node, err := parser.ParseFile(fset, f, nil, parser.ParseComments)
- if err != nil {
- log.Fatal(err)
+ // for _, f := range files {
+ fset := token.NewFileSet()
+ pkgs, err := parser.ParseDir(fset, p, nil, parser.ParseComments)
+ if err != nil {
+ log.Fatal(err)
+ }
+ for pkgName, pkg := range pkgs {
+ v := NewVisitor(pkgName)
+ for fileName, f := range pkg.Files {
+ v.file = fileName[:len(fileName)-3] + genFileSuffix
+ ast.Walk(v, f)
+ if err != nil {
+ log.Fatal(err)
+ }
}
- v := &vis{pkg: node.Name.String(), specs: make([]*ast.TypeSpec, 0), file: f}
- ast.Walk(v, node)
err = v.gen()
if err != nil {
log.Fatal(err)
diff --git a/gojay/tests/basic_slices.go b/gojay/tests/basic_slices.go
@@ -0,0 +1,16 @@
+package tests
+
+//gojay:json
+type StrSlice []string
+
+//gojay:json
+type IntSlice []int
+
+//gojay:json
+type BoolSlice []bool
+
+//gojay:json
+type StructSlice []*A
+
+//gojay:json
+type SliceSlice []*StrSlice
diff --git a/gojay/tests/basic_slices_gojay.go b/gojay/tests/basic_slices_gojay.go
@@ -0,0 +1,113 @@
+package tests
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
+func (v *BoolSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
+ var b bool
+ if err := dec.Bool(&b); err != nil {
+ return err
+ }
+ *v = append(*v, b)
+ return nil
+}
+
+// MarshalJSONArray implements gojay's MarshalerJSONArray
+func (v *BoolSlice) MarshalJSONArray(enc *gojay.Encoder) {
+ for _, s := range *v {
+ enc.Bool(s)
+ }
+}
+
+// IsNil implements gojay's MarshalerJSONArray
+func (v *BoolSlice) IsNil() bool {
+ return *v == nil || len(*v) == 0
+}
+
+// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
+func (v *StructSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
+ var s = &A{}
+ if err := dec.Object(s); err != nil {
+ return err
+ }
+ *v = append(*v, s)
+ return nil
+}
+
+// MarshalJSONArray implements gojay's MarshalerJSONArray
+func (v *StructSlice) MarshalJSONArray(enc *gojay.Encoder) {
+ for _, s := range *v {
+ enc.Object(s)
+ }
+}
+
+// IsNil implements gojay's MarshalerJSONArray
+func (v *StructSlice) IsNil() bool {
+ return *v == nil || len(*v) == 0
+}
+
+// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
+func (v *SliceSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
+ var s = make(StrSlice, 0)
+ if err := dec.Array(&s); err != nil {
+ return err
+ }
+ *v = append(*v, &s)
+ return nil
+}
+
+// MarshalJSONArray implements gojay's MarshalerJSONArray
+func (v *SliceSlice) MarshalJSONArray(enc *gojay.Encoder) {
+ for _, s := range *v {
+ enc.Array(s)
+ }
+}
+
+// IsNil implements gojay's MarshalerJSONArray
+func (v *SliceSlice) IsNil() bool {
+ return *v == nil || len(*v) == 0
+}
+
+// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
+func (v *StrSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
+ var str string
+ if err := dec.String(&str); err != nil {
+ return err
+ }
+ *v = append(*v, str)
+ return nil
+}
+
+// MarshalJSONArray implements gojay's MarshalerJSONArray
+func (v *StrSlice) MarshalJSONArray(enc *gojay.Encoder) {
+ for _, s := range *v {
+ enc.String(s)
+ }
+}
+
+// IsNil implements gojay's MarshalerJSONArray
+func (v *StrSlice) IsNil() bool {
+ return *v == nil || len(*v) == 0
+}
+
+// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
+func (v *IntSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
+ var i int
+ if err := dec.Int(&i); err != nil {
+ return err
+ }
+ *v = append(*v, i)
+ return nil
+}
+
+// MarshalJSONArray implements gojay's MarshalerJSONArray
+func (v *IntSlice) MarshalJSONArray(enc *gojay.Encoder) {
+ for _, s := range *v {
+ enc.Int(s)
+ }
+}
+
+// IsNil implements gojay's MarshalerJSONArray
+func (v *IntSlice) IsNil() bool {
+ return *v == nil || len(*v) == 0
+}
diff --git a/gojay/tests/basic_structs.go b/gojay/tests/basic_structs.go
@@ -14,19 +14,31 @@ type A struct {
Uint16 uint16
Uint8 uint8
Bval *B
+ Arrval *StrSlice
}
//gojay:json
type B struct {
- Str string
- Bool bool
- Int int
- Int64 int64
- Int32 int32
- Int16 int16
- Int8 int8
- Uint64 uint64
- Uint32 uint32
- Uint16 uint16
- Uint8 uint8
+ Str string
+ Bool bool
+ Int int
+ Int64 int64
+ Int32 int32
+ Int16 int16
+ Int8 int8
+ Uint64 uint64
+ Uint32 uint32
+ Uint16 uint16
+ Uint8 uint8
+ StrPtr *string
+ BoolPtr *bool
+ IntPtr *int
+ Int64Ptr *int64
+ Int32Ptr *int32
+ Int16Ptr *int16
+ Int8Ptr *int8
+ Uint64Ptr *uint64
+ Uint32Ptr *uint32
+ Uint16Ptr *uint16
+ Uint8PTr *uint8
}
diff --git a/gojay/tests/basic_structs_gojay.go b/gojay/tests/basic_structs_gojay.go
@@ -1,4 +1,4 @@
-package tests
+package tests
import "github.com/francoispqt/gojay"
@@ -32,12 +32,18 @@ func (v *A) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
v.Bval = &B{}
}
dec.Object(v.Bval)
+ case "arrval":
+ if v.Arrval == nil {
+ arr := make(StrSlice, 0)
+ v.Arrval = &arr
+ }
+ dec.Array(v.Arrval)
}
return nil
}
// NKeys returns the number of keys to unmarshal
-func (v *A) NKeys() int { return 12 }
+func (v *A) NKeys() int { return 13 }
// MarshalJSONObject implements gojay's MarshalerJSONObject
func (v *A) MarshalJSONObject(enc *gojay.Encoder) {
@@ -53,6 +59,7 @@ func (v *A) MarshalJSONObject(enc *gojay.Encoder) {
enc.Uint16Key("uint16", v.Uint16)
enc.Uint8Key("uint8", v.Uint8)
enc.ObjectKey("bval", v.Bval)
+ enc.ArrayKey("arrval", v.Arrval)
}
// IsNil returns wether the structure is nil value or not
@@ -83,12 +90,34 @@ func (v *B) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
return dec.Uint16(&v.Uint16)
case "uint8":
return dec.Uint8(&v.Uint8)
+ case "strptr":
+ return dec.String(v.StrPtr)
+ case "boolptr":
+ return dec.Bool(v.BoolPtr)
+ case "intptr":
+ return dec.Int(v.IntPtr)
+ case "int64ptr":
+ return dec.Int64(v.Int64Ptr)
+ case "int32ptr":
+ return dec.Int32(v.Int32Ptr)
+ case "int16ptr":
+ return dec.Int16(v.Int16Ptr)
+ case "int8ptr":
+ return dec.Int8(v.Int8Ptr)
+ case "uint64ptr":
+ return dec.Uint64(v.Uint64Ptr)
+ case "uint32ptr":
+ return dec.Uint32(v.Uint32Ptr)
+ case "uint16ptr":
+ return dec.Uint16(v.Uint16Ptr)
+ case "uint8ptr":
+ return dec.Uint8(v.Uint8PTr)
}
return nil
}
// NKeys returns the number of keys to unmarshal
-func (v *B) NKeys() int { return 11 }
+func (v *B) NKeys() int { return 22 }
// MarshalJSONObject implements gojay's MarshalerJSONObject
func (v *B) MarshalJSONObject(enc *gojay.Encoder) {
@@ -103,6 +132,17 @@ func (v *B) MarshalJSONObject(enc *gojay.Encoder) {
enc.Uint32Key("uint32", v.Uint32)
enc.Uint16Key("uint16", v.Uint16)
enc.Uint8Key("uint8", v.Uint8)
+ enc.StringKey("strptr", *v.StrPtr)
+ enc.BoolKey("boolptr", *v.BoolPtr)
+ enc.IntKey("intptr", *v.IntPtr)
+ enc.Int64Key("int64ptr", *v.Int64Ptr)
+ enc.Int32Key("int32ptr", *v.Int32Ptr)
+ enc.Int16Key("int16ptr", *v.Int16Ptr)
+ enc.Int8Key("int8ptr", *v.Int8Ptr)
+ enc.Uint64Key("uint64ptr", *v.Uint64Ptr)
+ enc.Uint32Key("uint32ptr", *v.Uint32Ptr)
+ enc.Uint16Key("uint16ptr", *v.Uint16Ptr)
+ enc.Uint8Key("uint8ptr", *v.Uint8PTr)
}
// IsNil returns wether the structure is nil value or not
diff --git a/gojay/visitor.go b/gojay/visitor.go
@@ -2,6 +2,7 @@ package main
import (
"go/ast"
+ "os"
"strings"
)
@@ -16,7 +17,8 @@ func docContains(n *ast.CommentGroup, s string) bool {
type vis struct {
pkg string
- specs []*ast.TypeSpec
+ specs map[string]*ast.TypeSpec
+ files map[string]map[string]*ast.TypeSpec
file string
commentFound bool
}
@@ -36,13 +38,42 @@ func (v *vis) Visit(n ast.Node) (w ast.Visitor) {
return v
case *ast.TypeSpec:
if v.commentFound {
- v.specs = append(v.specs, n)
+ v.specs[n.Name.Name] = n
+ if v.files[v.file] == nil {
+ v.files[v.file] = make(map[string]*ast.TypeSpec)
+ }
+ v.files[v.file][n.Name.Name] = n
}
v.commentFound = false
return v
case *ast.StructType:
v.commentFound = false
- return nil
+ return v
+ }
+ return v
+}
+
+func (v *vis) gen() error {
+ for fileName, genTypes := range v.files {
+ // open the file
+ f, err := os.OpenFile(fileName, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0777)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ g := &gen{f, genTypes, v}
+ err = g.gen(v.pkg)
+ if err != nil {
+ return err
+ }
}
return nil
}
+
+func NewVisitor(pkgName string) *vis {
+ return &vis{
+ pkg: pkgName,
+ specs: make(map[string]*ast.TypeSpec),
+ files: make(map[string]map[string]*ast.TypeSpec),
+ }
+}