OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / hashicorp / hcl / json / parser / flatten.go
1 package parser
2
3 import "github.com/hashicorp/hcl/hcl/ast"
4
5 // flattenObjects takes an AST node, walks it, and flattens
6 func flattenObjects(node ast.Node) {
7         ast.Walk(node, func(n ast.Node) (ast.Node, bool) {
8                 // We only care about lists, because this is what we modify
9                 list, ok := n.(*ast.ObjectList)
10                 if !ok {
11                         return n, true
12                 }
13
14                 // Rebuild the item list
15                 items := make([]*ast.ObjectItem, 0, len(list.Items))
16                 frontier := make([]*ast.ObjectItem, len(list.Items))
17                 copy(frontier, list.Items)
18                 for len(frontier) > 0 {
19                         // Pop the current item
20                         n := len(frontier)
21                         item := frontier[n-1]
22                         frontier = frontier[:n-1]
23
24                         switch v := item.Val.(type) {
25                         case *ast.ObjectType:
26                                 items, frontier = flattenObjectType(v, item, items, frontier)
27                         case *ast.ListType:
28                                 items, frontier = flattenListType(v, item, items, frontier)
29                         default:
30                                 items = append(items, item)
31                         }
32                 }
33
34                 // Reverse the list since the frontier model runs things backwards
35                 for i := len(items)/2 - 1; i >= 0; i-- {
36                         opp := len(items) - 1 - i
37                         items[i], items[opp] = items[opp], items[i]
38                 }
39
40                 // Done! Set the original items
41                 list.Items = items
42                 return n, true
43         })
44 }
45
46 func flattenListType(
47         ot *ast.ListType,
48         item *ast.ObjectItem,
49         items []*ast.ObjectItem,
50         frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) {
51         // If the list is empty, keep the original list
52         if len(ot.List) == 0 {
53                 items = append(items, item)
54                 return items, frontier
55         }
56
57         // All the elements of this object must also be objects!
58         for _, subitem := range ot.List {
59                 if _, ok := subitem.(*ast.ObjectType); !ok {
60                         items = append(items, item)
61                         return items, frontier
62                 }
63         }
64
65         // Great! We have a match go through all the items and flatten
66         for _, elem := range ot.List {
67                 // Add it to the frontier so that we can recurse
68                 frontier = append(frontier, &ast.ObjectItem{
69                         Keys:        item.Keys,
70                         Assign:      item.Assign,
71                         Val:         elem,
72                         LeadComment: item.LeadComment,
73                         LineComment: item.LineComment,
74                 })
75         }
76
77         return items, frontier
78 }
79
80 func flattenObjectType(
81         ot *ast.ObjectType,
82         item *ast.ObjectItem,
83         items []*ast.ObjectItem,
84         frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) {
85         // If the list has no items we do not have to flatten anything
86         if ot.List.Items == nil {
87                 items = append(items, item)
88                 return items, frontier
89         }
90
91         // All the elements of this object must also be objects!
92         for _, subitem := range ot.List.Items {
93                 if _, ok := subitem.Val.(*ast.ObjectType); !ok {
94                         items = append(items, item)
95                         return items, frontier
96                 }
97         }
98
99         // Great! We have a match go through all the items and flatten
100         for _, subitem := range ot.List.Items {
101                 // Copy the new key
102                 keys := make([]*ast.ObjectKey, len(item.Keys)+len(subitem.Keys))
103                 copy(keys, item.Keys)
104                 copy(keys[len(item.Keys):], subitem.Keys)
105
106                 // Add it to the frontier so that we can recurse
107                 frontier = append(frontier, &ast.ObjectItem{
108                         Keys:        keys,
109                         Assign:      item.Assign,
110                         Val:         subitem.Val,
111                         LeadComment: item.LeadComment,
112                         LineComment: item.LineComment,
113                 })
114         }
115
116         return items, frontier
117 }