Recursive implementation of the Walk methods. Takes care of avoiding infinite recursions by keeping track of types that have already been walked.
(at *expr.AttributeExpr, walker func(*expr.AttributeExpr) error, seen map[string]bool)
| 36 | // Recursive implementation of the Walk methods. Takes care of avoiding infinite |
| 37 | // recursions by keeping track of types that have already been walked. |
| 38 | func walk(at *expr.AttributeExpr, walker func(*expr.AttributeExpr) error, seen map[string]bool) error { |
| 39 | if err := walker(at); err != nil { |
| 40 | return err |
| 41 | } |
| 42 | walkUt := func(ut expr.UserType) error { |
| 43 | if _, ok := seen[ut.ID()]; ok { |
| 44 | return nil |
| 45 | } |
| 46 | seen[ut.ID()] = true |
| 47 | return walk(ut.Attribute(), walker, seen) |
| 48 | } |
| 49 | switch actual := at.Type.(type) { |
| 50 | case expr.Primitive: |
| 51 | return nil |
| 52 | case *expr.Array: |
| 53 | return walk(actual.ElemType, walker, seen) |
| 54 | case *expr.Map: |
| 55 | if err := walk(actual.KeyType, walker, seen); err != nil { |
| 56 | return err |
| 57 | } |
| 58 | return walk(actual.ElemType, walker, seen) |
| 59 | case *expr.Union: |
| 60 | for _, nat := range actual.Values { |
| 61 | if err := walk(nat.Attribute, walker, seen); err != nil { |
| 62 | return err |
| 63 | } |
| 64 | } |
| 65 | case *expr.Object: |
| 66 | for _, cat := range *actual { |
| 67 | if err := walk(cat.Attribute, walker, seen); err != nil { |
| 68 | return err |
| 69 | } |
| 70 | } |
| 71 | case *expr.UserTypeExpr: |
| 72 | return walkUt(actual) |
| 73 | case *expr.ResultTypeExpr: |
| 74 | return walkUt(actual.UserTypeExpr) |
| 75 | default: |
| 76 | panic("unknown attribute type") // bug |
| 77 | } |
| 78 | return nil |
| 79 | } |