@@ -12,27 +12,37 @@ import (
1212
1313var (
1414 // Config vars
15- pkg string
16- subpkg string
17- out string
18- fname string
19- fInfo os.FileInfo
15+ pkg string
16+ subpkg string
17+ out string
18+ fname string
19+ parseEmpty bool
20+ marshal bool
21+ unmarshal bool
22+
23+ fInfo os.FileInfo
2024
2125 // Package vars
2226 pkgCnt string
2327 f * File
2428 p = parser.Parser {AllStructs : true }
2529)
2630
31+ const fieldPrefix = "um"
32+
2733func main () {
28- flags := cli .New ("This app generates csv Marshall and Unmarshal functions" , "0 .0.2 " )
34+ flags := cli .New ("This app generates csv Marshall and Unmarshal functions" , "1 .0.1 " )
2935 flags .StringVarP (& pkg , "pkg" , "p" , "" , "output package" )
3036 flags .StringVarP (& subpkg , "subpkg" , "s" , "" , "output subpkg name" )
3137 flags .StringVarP (& fname , "fname" , "f" , "" , "input file" )
3238 flags .StringVarP (& out , "out" , "o" , "" , "output file" )
39+ flags .BoolVarP (& parseEmpty , "parseempty" , "e" , false , "parse empty fields with values: '', 0, 0.0, false. Default: false" )
40+ flags .BoolVarP (& marshal , "marshal" , "m" , true , "generate MarshalCSV or not" )
41+ flags .BoolVarP (& unmarshal , "unmarshal" , "u" , true , "generate UnmarshalCSV or not" )
3342
3443 flags .Parse ()
3544
45+ fmt .Println ("unmarshal:" , unmarshal , "\n " , "marshal:" , marshal )
3646 pkgCnt = "main"
3747 if pkg != "" {
3848 pkgCnt = pkg
@@ -122,27 +132,28 @@ func GenerateCode() {
122132}
123133
124134// GenerateFuncs processes every structure.
125- // Generated functions MarshallCSV and UnmarshallCSV process builtin types,
126- // call MarshallCSV and UnmarshallCSV for custom types
135+ // Generated functions MarshalCSV and UnmarshalCSV process builtin types,
136+ // call MarshalCSV and UnmarshalCSV for custom types
127137// and process pointer types assuming that pointers were initiated (memory is
128138// allocated).
129139// So the best way is to verify data structures before marshalling
130140// and unmarshalling for null pointers to prevent SEGFAULT
131141func GenerateFuncs (vstr parser.StructInfo ) {
132142
133- // func (this *Type) UnmarshalCSV(in []string) error {
134- // i := 0
135- // if x, err := strconv.ParseBool(in[i]); err == nil {
136- // this.b = x
137- // } else {
143+ // func (pv *Type) UnmarshalCSV(in []string) error {
144+ // if in == nil || len(in) < 2 {
145+ // return errors.New("Invalid input to UnmarshalCSV")
146+ // }
147+ // unm_b, err := strconv.ParseBool(in[0])
148+ // if err != nil {
138149 // return err
139150 // }
140- // i++
141- // if x, err := strconv.ParseInt(in[i], 10, 64); err == nil {
142- // this.a = x
143- // } else {
151+ // pv.b = b
152+ // unm_a, err := strconv.ParseInt(in[1], 10, 64)
153+ // if err == nil {
144154 // return err
145155 // }
156+ // this.a = a
146157 // }
147158 //
148159 // // func (this Type) MarshalCSV() []string {
@@ -156,11 +167,18 @@ func GenerateFuncs(vstr parser.StructInfo) {
156167 var unmarshallBody []Code
157168 var marshallBody []Code
158169
170+ chkError := If (
171+ Id ("in" ).Op ("==" ).Id ("nil" ).Op ("||" ).Id ("len" ).Call (Id ("in" )).Op ("<" ).Lit (len (vstr .Fields )),
172+ ).Block (
173+ Return ().Qual ("github.com/pkg/errors" , "New" ).Call (Lit ("Invalid input to *" + vstr .Name + " UnmarshalCSV" )),
174+ )
175+ unmarshallBody = append (unmarshallBody , chkError )
159176 unmarshallBody = append (unmarshallBody , Id ("i" ).Op (":=" ).Lit (0 ))
160177 marshallBody = append (marshallBody , Id ("out" ).Op (":=" ).Index ().String ().Values ())
161178
162179 for ik , istr := range vstr .Fields {
163- var g , j * Statement
180+ var g []Code
181+ var j * Statement
164182 star := ""
165183 ttype := istr .Type
166184 if istr .Type [0 ] == '*' {
@@ -170,22 +188,19 @@ func GenerateFuncs(vstr parser.StructInfo) {
170188
171189 unmarshallBody = append (unmarshallBody , nilCheck (star , istr .Name , istr .Type , false ))
172190 marshallBody = append (marshallBody , nilCheck (star , istr .Name , istr .Type , true ))
191+
173192 switch ttype {
174193 case "bool" :
175- g = If (
176- List (Id ("x" ), Err ()).Op (":=" ).Qual ("strconv" , "ParseBool" ).Call (Id ("in" ).Index (Id ("i" ))),
177- Err ().Op ("!=" ).Nil (),
178- ).Add (genReturn (star , istr .Name , ttype ))
179- j = marshalBody (Qual ("strconv" , "FormatBool" ).Call (Op (star ).Id ("this" ).Op ("." ).Id (istr .Name )))
194+ op := Qual ("strconv" , "ParseBool" ).Call (Id ("in" ).Index (Id ("i" )))
195+ g = parseField (star , istr .Name , ttype , op , "false" )
196+ j = marshalBody (Qual ("strconv" , "FormatBool" ).Call (Op (star ).Id ("pv" ).Op ("." ).Id (istr .Name )))
180197 case "float32" :
181198 fallthrough
182199 case "float64" :
183- g = If (
184- List (Id ("x" ), Err ()).Op (":=" ).Qual ("strconv" , "ParseFloat" ).Call (List (Id ("in" ).Index (Id ("i" )), Id (ttype [5 :]))),
185- Err ().Op ("!=" ).Nil (),
186- ).Add (genReturn (star , istr .Name , ttype ))
200+ op := Qual ("strconv" , "ParseFloat" ).Call (List (Id ("in" ).Index (Id ("i" )), Id (ttype [5 :])))
201+ g = parseField (star , istr .Name , ttype , op , "0.0" )
187202 j = marshalBody (Qual ("strconv" , "FormatFloat" ).
188- Call (Op ("float64" ).Call (Op (star ).Id ("this " ).Op ("." ).Id (istr .Name )),
203+ Call (Op ("float64" ).Call (Op (star ).Id ("pv " ).Op ("." ).Id (istr .Name )),
189204 LitRune ('f' ), Lit (- 1 ), Id (ttype [5 :])),
190205 )
191206 case "int" :
@@ -201,13 +216,10 @@ func GenerateFuncs(vstr parser.StructInfo) {
201216 if bn == "" {
202217 bn = "0"
203218 }
204- g = If (
205- List (Id ("x" ), Err ()).Op (":=" ).Qual ("strconv" , "ParseInt" ).
206- Call (List (Id ("in" ).Index (Id ("i" )), Lit (10 ), Id (bn ))),
207- Err ().Op ("!=" ).Nil (),
208- ).Add (genReturn (star , istr .Name , ttype ))
219+ op := Qual ("strconv" , "ParseInt" ).Call (List (Id ("in" ).Index (Id ("i" )), Lit (10 ), Id (bn )))
220+ g = parseField (star , istr .Name , ttype , op , "0" )
209221 j = marshalBody (Qual ("strconv" , "FormatInt" ).
210- Call (Op ("int64" ).Call (Op (star ).Id ("this " ).Op ("." ).Id (istr .Name )), Lit (10 )),
222+ Call (Op ("int64" ).Call (Op (star ).Id ("pv " ).Op ("." ).Id (istr .Name )), Lit (10 )),
211223 )
212224 case "uint" :
213225 fallthrough
@@ -222,29 +234,30 @@ func GenerateFuncs(vstr parser.StructInfo) {
222234 if bn == "" {
223235 bn = "0"
224236 }
225- g = If (
226- List (Id ("x" ), Err ()).Op (":=" ).Qual ("strconv" , "ParseUint" ).
227- Call (List (Id ("in" ).Index (Id ("i" )), Lit (10 ), Id (bn ))),
228- Err ().Op ("!=" ).Nil (),
229- ).Add (genReturn (star , istr .Name , ttype ))
237+ op := Qual ("strconv" , "ParseUint" ).Call (List (Id ("in" ).Index (Id ("i" )), Lit (10 ), Id (bn )))
238+ g = parseField (star , istr .Name , ttype , op , "0" )
230239 j = marshalBody (Qual ("strconv" , "FormatUint" ).
231- Call (Op ("uint64" ).Call (Op (star ).Id ("this " ).Op ("." ).Id (istr .Name )), Lit (10 )),
240+ Call (Op ("uint64" ).Call (Op (star ).Id ("pv " ).Op ("." ).Id (istr .Name )), Lit (10 )),
232241 )
233242 case "string" :
234- g = Op (star ).Id ("this" ).Op ("." ).Id (istr .Name ).Op ("=" ).Id ("in" ).Index (Id ("i" ))
235- j = marshalBody (Op (star ).Id ("this" ).Op ("." ).Id (istr .Name ))
243+ g = []Code {
244+ Op (star ).Id ("pv" ).Op ("." ).Id (istr .Name ).Op ("=" ).Id ("in" ).Index (Id ("i" )),
245+ }
246+ j = marshalBody (Op (star ).Id ("pv" ).Op ("." ).Id (istr .Name ))
236247 default :
237- // By default generated code calls 'func (this *Type) UnmarshallCSV(s string) error'
238- g = If (
239- Err ().Op (":=" ).Id ("this" ).Op ("." ).Id (istr .Name ).Op ("." ).Id ("UnmarshallCSV" ).
240- Call (Id ("in" ).Index (Id ("i" ))),
241- Err ().Op ("!=" ).Nil (),
242- ).Block (
243- Return ().Err (),
244- )
245- // By default generated code calls 'func (this Type) MarshallCSV() (string, error)'
248+ // By default generated code calls 'func (this *Type) UnmarshalCSV(s string) error'
249+ g = []Code {
250+ If (
251+ Err ().Op (":=" ).Id ("pv" ).Op ("." ).Id (istr .Name ).Op ("." ).Id ("UnmarshalCSV" ).
252+ Call (Id ("in" ).Index (Id ("i" ))),
253+ Err ().Op ("!=" ).Nil (),
254+ ).Block (
255+ Return ().Err (),
256+ ),
257+ }
258+ // By default generated code calls 'func (this Type) MarshalCSV() (string, error)'
246259 j = If (
247- List (Id ("mt" ), Err ()).Op (":=" ).Id ("this " ).Op ("." ).Id (istr .Name ).Op ("." ).Id ("MarshallCSV " ).
260+ List (Id ("mt" ), Err ()).Op (":=" ).Id ("pv " ).Op ("." ).Id (istr .Name ).Op ("." ).Id ("MarshalCSV " ).
248261 Call (),
249262 Err ().Op ("!=" ).Nil (),
250263 ).Block (
@@ -253,7 +266,7 @@ func GenerateFuncs(vstr parser.StructInfo) {
253266 marshalBody (Id ("mt" )),
254267 )
255268 }
256- unmarshallBody = append (unmarshallBody , g )
269+ unmarshallBody = append (unmarshallBody , g ... )
257270 marshallBody = append (marshallBody , j )
258271 if ik != (len (vstr .Fields ) - 1 ) {
259272 unmarshallBody = append (unmarshallBody , Id ("i" ).Op ("++" ))
@@ -263,56 +276,90 @@ func GenerateFuncs(vstr parser.StructInfo) {
263276 }
264277 }
265278
266- f .Comment ("UnmarshalCSV " + vstr .Name + " func" )
267- f .Func ().Params (
268- Id ("this" ).Op ("*" ).Id (vstr .Name ),
269- ).Id ("UnmarshalCSV" ).Params (
270- Id ("in" ).Index ().String (),
271- ).Id ("error" ).Block (
272- unmarshallBody ... ,
273- )
279+ if unmarshal {
280+ f .Comment ("UnmarshalCSV " + vstr .Name + " func" )
281+ f .Func ().Params (
282+ Id ("pv" ).Op ("*" ).Id (vstr .Name ),
283+ ).Id ("UnmarshalCSV" ).Params (
284+ Id ("in" ).Index ().String (),
285+ ).Id ("error" ).Block (
286+ unmarshallBody ... ,
287+ )
274288
275- f .Line ()
289+ f .Line ()
290+ }
276291
277- f .Comment ("MarshalCSV " + vstr .Name + " func" )
278- f .Func ().Params (
279- Id ("this" ).Id (vstr .Name ),
280- ).Id ("MarshalCSV" ).Params ().
281- Parens (Index ().String ().Op ("," ).Id ("error" )).Block (
282- marshallBody ... ,
283- )
292+ if marshal {
293+ f .Comment ("MarshalCSV " + vstr .Name + " func" )
294+ f .Func ().Params (
295+ Id ("pv" ).Id (vstr .Name ),
296+ ).Id ("MarshalCSV" ).Params ().
297+ Parens (Index ().String ().Op ("," ).Id ("error" )).Block (
298+ marshallBody ... ,
299+ )
300+ }
301+
302+ if unmarshal {
303+ AddList (vstr )
304+ }
284305}
285306
286- func genReturn (star string , fieldName string , fieldType string ) * Statement {
307+ func parseField (star string , fieldName string , fieldType string , op * Statement , defv string ) []Code {
308+ fldNm := fieldPrefix + strings .Title (fieldName )
309+ parseBlock := []Code {
310+ List (Id (fldNm ), Err ()).Op (":=" ).Add (op ),
311+ If (
312+ Err ().Op ("!=" ).Nil (),
313+ ).Block (
314+ Return ().Err (),
315+ ),
316+ }
317+
287318 var conv * Statement
288319
289320 // Check for float and int
290321 if fieldType [len (fieldType )- 2 :] != "64" {
291- conv = Id (fieldType ).Call (Id ("x" ))
322+ conv = Id (fieldType ).Call (Id (fldNm ))
292323 } else {
293- conv = Id ("x" )
324+ conv = Id (fldNm )
294325 }
295- return Block (
296- Return ().Err (),
297- ).Else ().Block (
298- Op (star ).Id ("this" ).Op ("." ).Id (fieldName ).Op ("=" ).Add (conv ),
299- )
326+
327+ parseBlock = append (parseBlock , Op (star ).Id ("pv" ).Op ("." ).Id (fieldName ).Op ("=" ).Add (conv ))
328+
329+ // Parse empty string with type rules
330+ // if in[i] == "" {
331+ // pv.Pp = 0
332+ // } else {
333+ // ...
334+ // }
335+ if parseEmpty {
336+ parseBlock = []Code {
337+ If (
338+ Id ("in" ).Index (Id ("i" )).Op ("==" ).Lit ("" ),
339+ ).Block (
340+ Op (star ).Id ("pv" ).Op ("." ).Id (fieldName ).Op ("=" ).Id (defv ),
341+ ).Else ().Block (
342+ parseBlock ... ,
343+ ),
344+ }
345+ }
346+ return parseBlock
300347}
301348
302349func marshalBody (typeRes * Statement ) * Statement {
303- return Id ("out" ).Op ("=" ).Id ( "append" ). Call (Id ("out" ), Add (typeRes ))
350+ return Id ("out" ).Op ("=" ).Append (Id ("out" ), Add (typeRes ))
304351}
305352
306353func nilCheck (star string , iname , itype string , marshall bool ) * Statement {
307354 var s , t * Statement
308355 if marshall {
309- t = List (Id ("out" ), Qual ("errors" , "New" ).Call (Lit ("nil pointer found at " + iname + " " + itype )))
356+ t = List (Id ("out" ), Qual ("github.com/pkg/ errors" , "New" ).Call (Lit ("nil pointer found at " + iname + " " + itype )))
310357 } else {
311- t = Qual ("errors" , "New" ).Call (Lit ("nil pointer found at " + iname + " " + itype ))
358+ t = Qual ("github.com/pkg/ errors" , "New" ).Call (Lit ("nil pointer found at " + iname + " " + itype ))
312359 }
313360 if star == "*" {
314361 s = If (
315- Id ("this " ).Op ("." ).Id (iname ).Op ("==" ).Id ("nil" ),
362+ Id ("pv " ).Op ("." ).Id (iname ).Op ("==" ).Id ("nil" ),
316363 ).Block (
317364 Return ().Add (t ),
318365 )
@@ -321,3 +368,44 @@ func nilCheck(star string, iname, itype string, marshall bool) *Statement {
321368 }
322369 return s
323370}
371+
372+ func AddList (vstr parser.StructInfo ) {
373+ // type FooList []Foo
374+
375+ // func (pl *FooList) Push(in []string) error {
376+ // nf := Foo{}
377+ // if err := nf.UnmarshalCSV(in); err != nil {
378+ // return errors.Wrap(err, "Error in UnmarshalCSV Foo")
379+ // }
380+ // *pl = append(*pl, nf)
381+ // return nil
382+ // }
383+
384+ f .Line ()
385+
386+ f .Comment (vstr .Name + "List csvparse.Pusher implementation" )
387+ f .Type ().Id (vstr .Name + "List" ).Index ().Id (vstr .Name )
388+
389+ f .Line ()
390+
391+ f .Comment ("Push function for " + vstr .Name + "List struct" )
392+ f .Func ().Params (
393+ Id ("pl" ).Op ("*" ).Id (vstr .Name + "List" ),
394+ ).Id ("Push" ).Params (Id ("in" ).Index ().String ()).
395+ Parens (Error ()).Block (
396+ Id ("nf" ).Op (":=" ).Id (vstr .Name ).Values (),
397+ If (
398+ Err ().Op (":=" ).Id ("nf" ).Op ("." ).Id ("UnmarshalCSV" ).Call (Id ("in" )),
399+ Err ().Op ("!=" ).Nil (),
400+ ).Block (
401+ Return (Qual ("github.com/pkg/errors" , "Wrapf" ).Call (
402+ Err (),
403+ Lit ("Error in UnmarshalCSV " + vstr .Name + " in line %#v " ),
404+ Id ("in" )),
405+ ),
406+ ),
407+ Op ("*" ).Id ("pl" ).Op ("=" ).Append (Op ("*" ).Id ("pl" ), Id ("nf" )),
408+ Return (Id ("nil" )),
409+ )
410+
411+ }
0 commit comments