OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / hashicorp / hcl / json / parser / flatten.go
diff --git a/vendor/github.com/hashicorp/hcl/json/parser/flatten.go b/vendor/github.com/hashicorp/hcl/json/parser/flatten.go
new file mode 100644 (file)
index 0000000..f652d6f
--- /dev/null
@@ -0,0 +1,117 @@
+package parser
+
+import "github.com/hashicorp/hcl/hcl/ast"
+
+// flattenObjects takes an AST node, walks it, and flattens
+func flattenObjects(node ast.Node) {
+       ast.Walk(node, func(n ast.Node) (ast.Node, bool) {
+               // We only care about lists, because this is what we modify
+               list, ok := n.(*ast.ObjectList)
+               if !ok {
+                       return n, true
+               }
+
+               // Rebuild the item list
+               items := make([]*ast.ObjectItem, 0, len(list.Items))
+               frontier := make([]*ast.ObjectItem, len(list.Items))
+               copy(frontier, list.Items)
+               for len(frontier) > 0 {
+                       // Pop the current item
+                       n := len(frontier)
+                       item := frontier[n-1]
+                       frontier = frontier[:n-1]
+
+                       switch v := item.Val.(type) {
+                       case *ast.ObjectType:
+                               items, frontier = flattenObjectType(v, item, items, frontier)
+                       case *ast.ListType:
+                               items, frontier = flattenListType(v, item, items, frontier)
+                       default:
+                               items = append(items, item)
+                       }
+               }
+
+               // Reverse the list since the frontier model runs things backwards
+               for i := len(items)/2 - 1; i >= 0; i-- {
+                       opp := len(items) - 1 - i
+                       items[i], items[opp] = items[opp], items[i]
+               }
+
+               // Done! Set the original items
+               list.Items = items
+               return n, true
+       })
+}
+
+func flattenListType(
+       ot *ast.ListType,
+       item *ast.ObjectItem,
+       items []*ast.ObjectItem,
+       frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) {
+       // If the list is empty, keep the original list
+       if len(ot.List) == 0 {
+               items = append(items, item)
+               return items, frontier
+       }
+
+       // All the elements of this object must also be objects!
+       for _, subitem := range ot.List {
+               if _, ok := subitem.(*ast.ObjectType); !ok {
+                       items = append(items, item)
+                       return items, frontier
+               }
+       }
+
+       // Great! We have a match go through all the items and flatten
+       for _, elem := range ot.List {
+               // Add it to the frontier so that we can recurse
+               frontier = append(frontier, &ast.ObjectItem{
+                       Keys:        item.Keys,
+                       Assign:      item.Assign,
+                       Val:         elem,
+                       LeadComment: item.LeadComment,
+                       LineComment: item.LineComment,
+               })
+       }
+
+       return items, frontier
+}
+
+func flattenObjectType(
+       ot *ast.ObjectType,
+       item *ast.ObjectItem,
+       items []*ast.ObjectItem,
+       frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) {
+       // If the list has no items we do not have to flatten anything
+       if ot.List.Items == nil {
+               items = append(items, item)
+               return items, frontier
+       }
+
+       // All the elements of this object must also be objects!
+       for _, subitem := range ot.List.Items {
+               if _, ok := subitem.Val.(*ast.ObjectType); !ok {
+                       items = append(items, item)
+                       return items, frontier
+               }
+       }
+
+       // Great! We have a match go through all the items and flatten
+       for _, subitem := range ot.List.Items {
+               // Copy the new key
+               keys := make([]*ast.ObjectKey, len(item.Keys)+len(subitem.Keys))
+               copy(keys, item.Keys)
+               copy(keys[len(item.Keys):], subitem.Keys)
+
+               // Add it to the frontier so that we can recurse
+               frontier = append(frontier, &ast.ObjectItem{
+                       Keys:        keys,
+                       Assign:      item.Assign,
+                       Val:         subitem.Val,
+                       LeadComment: item.LeadComment,
+                       LineComment: item.LineComment,
+               })
+       }
+
+       return items, frontier
+}