@@ -63,40 +63,30 @@ func GoTransform(source, target *expr.AttributeExpr, sourceVar, targetVar string
63
63
// transformAttribute returns the code to transform source attribute to target
64
64
// attribute. It returns an error if source and target are not compatible for
65
65
// transformation.
66
- func transformAttribute (source , target * expr.AttributeExpr , sourceVar , targetVar string , newVar bool , ta * TransformAttrs ) (string , error ) {
67
- var err error
68
- {
69
- if err = IsCompatible (source .Type , target .Type , sourceVar , targetVar ); err != nil {
70
- return "" , err
71
- }
66
+ func transformAttribute (source , target * expr.AttributeExpr , sourceVar , targetVar string , newVar bool , ta * TransformAttrs ) (code string , err error ) {
67
+ if err = IsCompatible (source .Type , target .Type , sourceVar , targetVar ); err != nil {
68
+ return
72
69
}
73
-
74
- var code string
75
- {
76
- switch {
77
- case expr .IsArray (source .Type ):
78
- code , err = transformArray (expr .AsArray (source .Type ), expr .AsArray (target .Type ), sourceVar , targetVar , newVar , ta )
79
- case expr .IsMap (source .Type ):
80
- code , err = transformMap (expr .AsMap (source .Type ), expr .AsMap (target .Type ), sourceVar , targetVar , newVar , ta )
81
- case expr .IsObject (source .Type ):
82
- code , err = transformObject (source , target , sourceVar , targetVar , newVar , ta )
83
- default :
84
- assign := "="
85
- if newVar {
86
- assign = ":="
87
- }
88
- if _ , ok := target .Type .(expr.UserType ); ok {
89
- // Primitive user type, these are used for error results
90
- cast := ta .TargetCtx .Scope .Ref (target , ta .TargetCtx .Pkg )
91
- return fmt .Sprintf ("%s %s %s(%s)\n " , targetVar , assign , cast , sourceVar ), nil
92
- }
93
- code = fmt .Sprintf ("%s %s %s\n " , targetVar , assign , sourceVar )
70
+ switch {
71
+ case expr .IsArray (source .Type ):
72
+ code , err = transformArray (expr .AsArray (source .Type ), expr .AsArray (target .Type ), sourceVar , targetVar , newVar , ta )
73
+ case expr .IsMap (source .Type ):
74
+ code , err = transformMap (expr .AsMap (source .Type ), expr .AsMap (target .Type ), sourceVar , targetVar , newVar , ta )
75
+ case expr .IsObject (source .Type ):
76
+ code , err = transformObject (source , target , sourceVar , targetVar , newVar , ta )
77
+ default :
78
+ assign := "="
79
+ if newVar {
80
+ assign = ":="
94
81
}
82
+ if _ , ok := target .Type .(expr.UserType ); ok {
83
+ // Primitive user type, these are used for error results
84
+ cast := ta .TargetCtx .Scope .Ref (target , ta .TargetCtx .Pkg )
85
+ return fmt .Sprintf ("%s %s %s(%s)\n " , targetVar , assign , cast , sourceVar ), nil
86
+ }
87
+ code = fmt .Sprintf ("%s %s %s\n " , targetVar , assign , sourceVar )
95
88
}
96
- if err != nil {
97
- return "" , err
98
- }
99
- return code , nil
89
+ return
100
90
}
101
91
102
92
// transformObject generates Go code to transform source object to target
@@ -335,141 +325,86 @@ func transformMapElem(source, target *expr.Map, sourceVar, targetVar string, new
335
325
// transformAttributeHelpers returns the Go transform functions and their definitions
336
326
// that may be used in code produced by Transform. It returns an error if source and
337
327
// target are incompatible (different types, fields of different type etc).
328
+ // transformAttributeHelpers recurses through the attribute types and calls
329
+ // collectHelpers for each child attribute. collectHelpers actually produces the
330
+ // transform helper functions for the given attribute.
338
331
//
339
332
// source, target are the source and target attributes used in transformation
340
333
//
341
334
// ta holds the transform attributes
342
335
//
343
- // seen keeps track of generated transform functions to avoid recursion
336
+ // seen keeps track of generated transform functions to avoid infinite recursion.
344
337
//
345
- func transformAttributeHelpers (source , target * expr.AttributeExpr , ta * TransformAttrs , seen map [string ]* TransformFunctionData ) ([]* TransformFunctionData , error ) {
346
- var (
347
- helpers []* TransformFunctionData
348
- err error
349
- )
350
- {
351
- // Do not generate a transform function for the top most user type.
352
- switch {
353
- case expr .IsArray (source .Type ):
354
- source = expr .AsArray (source .Type ).ElemType
355
- target = expr .AsArray (target .Type ).ElemType
356
- helpers , err = transformAttributeHelpers (source , target , ta , seen )
357
- case expr .IsMap (source .Type ):
358
- sm := expr .AsMap (source .Type )
359
- tm := expr .AsMap (target .Type )
360
- helpers , err = transformAttributeHelpers (sm .ElemType , tm .ElemType , ta , seen )
361
- if err == nil {
362
- var other []* TransformFunctionData
363
- other , err = transformAttributeHelpers (sm .KeyType , tm .KeyType , ta , seen )
364
- helpers = append (helpers , other ... )
365
- }
366
- case expr .IsObject (source .Type ):
367
- walkMatches (source , target , func (srcMatt , tgtMatt * expr.MappedAttributeExpr , srcc , tgtc * expr.AttributeExpr , n string ) {
368
- if err != nil {
369
- return
370
- }
371
- h , err2 := collectHelpers (srcc , tgtc , srcMatt .IsRequired (n ), ta , seen )
372
- if err2 != nil {
373
- err = err2
374
- return
375
- }
376
- helpers = append (helpers , h ... )
377
- })
338
+ func transformAttributeHelpers (source , target * expr.AttributeExpr , ta * TransformAttrs , seen map [string ]* TransformFunctionData ) (helpers []* TransformFunctionData , err error ) {
339
+ // Do not generate a transform function for the top most user type.
340
+ switch {
341
+ case expr .IsArray (source .Type ):
342
+ helpers , err = transformAttributeHelpers (expr .AsArray (source .Type ).ElemType , expr .AsArray (target .Type ).ElemType , ta , seen )
343
+ case expr .IsMap (source .Type ):
344
+ sm , tm := expr .AsMap (source .Type ), expr .AsMap (target .Type )
345
+ helpers , err = transformAttributeHelpers (sm .ElemType , tm .ElemType , ta , seen )
346
+ if err == nil {
347
+ var other []* TransformFunctionData
348
+ other , err = collectHelpers (sm .KeyType , tm .KeyType , true , ta , seen )
349
+ helpers = append (helpers , other ... )
378
350
}
351
+ case expr .IsObject (source .Type ):
352
+ walkMatches (source , target , func (srcMatt , _ * expr.MappedAttributeExpr , srcc , tgtc * expr.AttributeExpr , n string ) {
353
+ if err != nil {
354
+ return
355
+ }
356
+ var hs []* TransformFunctionData
357
+ hs , err = collectHelpers (srcc , tgtc , srcMatt .IsRequired (n ), ta , seen )
358
+ helpers = append (helpers , hs ... )
359
+ })
379
360
}
380
- if err != nil {
381
- return nil , err
382
- }
383
- return helpers , nil
361
+ return
384
362
}
385
363
386
- // collectHelpers recursively traverses the given attributes and return the
387
- // transform helper functions required to generate the transform code.
388
- func collectHelpers (source , target * expr.AttributeExpr , req bool , ta * TransformAttrs , seen map [string ]* TransformFunctionData ) ([]* TransformFunctionData , error ) {
389
- var (
390
- data []* TransformFunctionData
391
- )
364
+ // collectHelpers recurses through the given attributes and returns the transform
365
+ // helper functions required to generate the transform code. If the attributes type
366
+ // is array or map then the recursion is done via transformAttributeHelpers so that
367
+ // the tope level conversion function is skipped as the generate code does not make
368
+ // use of it (since it inlines that top-level transformation).
369
+ func collectHelpers (source , target * expr.AttributeExpr , req bool , ta * TransformAttrs , seen map [string ]* TransformFunctionData ) (helpers []* TransformFunctionData , err error ) {
370
+ name := transformHelperName (source , target , ta )
371
+ if _ , ok := seen [name ]; ok {
372
+ return
373
+ }
374
+ if _ , ok := source .Type .(expr.UserType ); ok {
375
+ var h * TransformFunctionData
376
+ if h , err = generateHelper (source , target , req , ta , seen ); h != nil {
377
+ helpers = append (helpers , h )
378
+ }
379
+ }
392
380
switch {
393
381
case expr .IsArray (source .Type ):
394
- st , tt := expr .AsArray (source .Type ).ElemType , expr .AsArray (target .Type ).ElemType
395
- if _ , ok := st .Type .(expr.UserType ); ok {
396
- // Handle array of user types explicitly to avoid infinite recursions
397
- // when the user type has an attribute of type array of itself.
398
- d , err := generateHelper (st , tt , req , ta , seen )
399
- if err != nil {
400
- return nil , err
401
- }
402
- if d != nil {
403
- data = append (data , d )
404
- }
405
- } else {
406
- helpers , err := transformAttributeHelpers (st , tt , ta , seen )
407
- if err != nil {
408
- return nil , err
409
- }
410
- data = append (data , helpers ... )
411
- }
382
+ helpers , err = collectHelpers (expr .AsArray (source .Type ).ElemType , expr .AsArray (target .Type ).ElemType , req , ta , seen )
412
383
case expr .IsMap (source .Type ):
413
- se , te := expr .AsMap (source .Type ).ElemType , expr .AsMap (target .Type ).ElemType
414
- sk , tk := expr .AsMap (source .Type ).KeyType , expr .AsMap (target .Type ).KeyType
415
- helpers , err := transformAttributeHelpers (sk , tk , ta , seen )
416
- if err != nil {
417
- return nil , err
418
- }
419
- data = append (data , helpers ... )
420
- if _ , ok := se .Type .(expr.UserType ); ok {
421
- // Handle map of user types explicitly to avoid infinite recursions
422
- // when the user type has an attribute of type map of itself.
423
- d , err := generateHelper (se , te , req , ta , seen )
424
- if err != nil {
425
- return nil , err
426
- }
427
- if d != nil {
428
- data = append (data , d )
429
- }
430
- } else {
431
- helpers , err = transformAttributeHelpers (se , te , ta , seen )
432
- if err != nil {
433
- return nil , err
434
- }
435
- data = append (data , helpers ... )
384
+ sm , tm := expr .AsMap (source .Type ), expr .AsMap (target .Type )
385
+ helpers , err = collectHelpers (sm .ElemType , tm .ElemType , req , ta , seen )
386
+ if err == nil {
387
+ var other []* TransformFunctionData
388
+ other , err = collectHelpers (sm .KeyType , tm .KeyType , req , ta , seen )
389
+ helpers = append (helpers , other ... )
436
390
}
437
391
case expr .IsObject (source .Type ):
438
- if _ , ok := source .Type .(expr.UserType ); ok {
439
- d , err := generateHelper (source , target , req , ta , seen )
392
+ walkMatches (source , target , func (srcMatt , _ * expr.MappedAttributeExpr , srcc , tgtc * expr.AttributeExpr , n string ) {
440
393
if err != nil {
441
- return nil , err
442
- }
443
- if d != nil {
444
- data = append (data , d )
394
+ return
445
395
}
446
- }
447
-
448
- // collect helpers
449
- var err error
450
- {
451
- walkMatches (source , target , func (srcMatt , _ * expr.MappedAttributeExpr , srcc , tgtc * expr.AttributeExpr , n string ) {
452
- name := transformHelperName (srcc , tgtc , ta )
453
- if _ , ok := seen [name ]; ok {
454
- return
455
- }
456
- var helpers []* TransformFunctionData
457
- helpers , err = collectHelpers (srcc , tgtc , srcMatt .IsRequired (n ), ta , seen )
458
- if err != nil {
459
- return
460
- }
461
- data = append (data , helpers ... )
462
- })
463
- }
464
- if err != nil {
465
- return nil , err
466
- }
396
+ var hs []* TransformFunctionData
397
+ hs , err = collectHelpers (srcc , tgtc , srcMatt .IsRequired (n ), ta , seen )
398
+ helpers = append (helpers , hs ... )
399
+ })
467
400
}
468
- return data , nil
401
+ return
469
402
}
470
403
471
404
// generateHelper generates the code that transform instances of source into
472
- // target.
405
+ // target. Both source and targe must be user types or generateHelper panics.
406
+ // generateHelper returns nil if a helper has already been generated for the
407
+ // pair source, target.
473
408
func generateHelper (source , target * expr.AttributeExpr , req bool , ta * TransformAttrs , seen map [string ]* TransformFunctionData ) (* TransformFunctionData , error ) {
474
409
name := transformHelperName (source , target , ta )
475
410
if _ , ok := seen [name ]; ok {
@@ -492,8 +427,10 @@ func generateHelper(source, target *expr.AttributeExpr, req bool, ta *TransformA
492
427
return tfd , nil
493
428
}
494
429
495
- // walkMatches iterates through the source attribute expression and executes
496
- // the walker function.
430
+ // walkMatches iterates through the attributes of source and looks for
431
+ // attributes with identical names in target. walkMatches calls the walker
432
+ // function for each pair of matched attributes. Both source and target must be
433
+ // objects or else walkMatches panics.
497
434
func walkMatches (source , target * expr.AttributeExpr , walker func (src , tgt * expr.MappedAttributeExpr , srcc , tgtc * expr.AttributeExpr , n string )) {
498
435
srcMatt := expr .NewMappedAttributeExpr (source )
499
436
tgtMatt := expr .NewMappedAttributeExpr (target )
0 commit comments