func (p *printer) output(n interface{}) []byte {
	var buf bytes.Buffer
	switch t := n.(type) {
	case *ast.File:
		return p.output(t.Node)
	case *ast.ObjectList:
		var index int
		var nextItem token.Pos
		var commented bool
		for {
			for _, c := range p.standaloneComments {
				for _, comment := range c.List {
					if index != len(t.Items) {
						nextItem = t.Items[index].Pos()
					} else {
						nextItem = token.Pos{Offset: infinity, Line: infinity}
					}
					if comment.Pos().After(p.prev) && comment.Pos().Before(nextItem) {
						if index == len(t.Items) {
							buf.Write([]byte{newline, newline})
						}
						buf.WriteString(comment.Text)
						buf.WriteByte(newline)
						if index != len(t.Items) {
							buf.WriteByte(newline)
						}
					}
				}
			}
			if index == len(t.Items) {
				break
			}
			buf.Write(p.output(t.Items[index]))
			if !commented && index != len(t.Items)-1 {
				buf.Write([]byte{newline, newline})
			}
			index++
		}
	case *ast.ObjectKey:
		buf.WriteString(t.Token.Text)
	case *ast.ObjectItem:
		p.prev = t.Pos()
		buf.Write(p.objectItem(t))
	case *ast.LiteralType:
		buf.WriteString(t.Token.Text)
	case *ast.ListType:
		buf.Write(p.list(t))
	case *ast.ObjectType:
		buf.Write(p.objectType(t))
	default:
		fmt.Printf(" unknown type: %T\n", n)
	}
	return buf.Bytes()
}
output prints creates b printable HCL output and returns it.
package printer
import (
	"bytes"
	"fmt"
	"sort"
	"github.com/fatih/hcl/ast"
	"github.com/fatih/hcl/token"
)
const (
	blank    = byte(' ')
	newline  = byte('\n')
	tab      = byte('\t')
	infinity = 1 << 30  
)
type printer struct {
	cfg  Config
	prev token.Pos
	comments           []*ast.CommentGroup  
	standaloneComments []*ast.CommentGroup  
	enableTrace bool
	indentTrace int
}
type ByPosition []*ast.CommentGroup
func (b ByPosition) Len() int           { return len(b) }
func (b ByPosition) Swap(i, j int)      { b[i], b[j] = b[j], b[i] }
func (b ByPosition) Less(i, j int) bool { return b[i].Pos().Before(b[j].Pos()) }
func (p *printer) collectComments(node ast.Node) {
	ast.Walk(node, func(nn ast.Node) bool {
		switch t := nn.(type) {
		case *ast.File:
			p.comments = t.Comments
			return false
		}
		return true
	})
	standaloneComments := make(map[token.Pos]*ast.CommentGroup, 0)
	for _, c := range p.comments {
		standaloneComments[c.Pos()] = c
	}
	ast.Walk(node, func(nn ast.Node) bool {
		switch t := nn.(type) {
		case *ast.LiteralType:
			if t.LineComment != nil {
				for _, comment := range t.LineComment.List {
					if _, ok := standaloneComments[comment.Pos()]; ok {
						delete(standaloneComments, comment.Pos())
					}
				}
			}
		case *ast.ObjectItem:
			if t.LeadComment != nil {
				for _, comment := range t.LeadComment.List {
					if _, ok := standaloneComments[comment.Pos()]; ok {
						delete(standaloneComments, comment.Pos())
					}
				}
			}
			if t.LineComment != nil {
				for _, comment := range t.LineComment.List {
					if _, ok := standaloneComments[comment.Pos()]; ok {
						delete(standaloneComments, comment.Pos())
					}
				}
			}
		}
		return true
	})
	for _, c := range standaloneComments {
		p.standaloneComments = append(p.standaloneComments, c)
	}
	sort.Sort(ByPosition(p.standaloneComments))
}