func (p *Parser) objectType() (*ast.ObjectType, error) {
	defer un(trace(p, "ParseObjectType"))
	o := &ast.ObjectType{
		Lbrace: p.tok.Pos,
	}
	l, err := p.objectList(true)
	if err != nil && p.tok.Type != token.RBRACE {
		return nil, err
	}
	if tok := p.scan(); tok.Type != token.RBRACE {
		return nil, &PosError{
			Pos: tok.Pos,
			Err: fmt.Errorf("object expected closing RBRACE got: %s", tok.Type),
		}
	}
	o.List = l
	o.Rbrace = p.tok.Pos  
	return o, nil
}
objectType parses an object type and returns a ObjectType AST
package parser
import (
	"bytes"
	"errors"
	"fmt"
	"strings"
	"github.com/hashicorp/hcl/hcl/ast"
	"github.com/hashicorp/hcl/hcl/scanner"
	"github.com/hashicorp/hcl/hcl/token"
)
type Parser struct {
	sc *scanner.Scanner
	tok       token.Token
	commaPrev token.Token
	comments    []*ast.CommentGroup
	leadComment *ast.CommentGroup  
	lineComment *ast.CommentGroup  
	enableTrace bool
	indent      int
	n           int  
}
func newParser(src []byte) *Parser {
	return &Parser{
		sc: scanner.New(src),
	}
}
func Parse(src []byte) (*ast.File, error) {
	src = bytes.Replace(src, []byte("\r\n"), []byte("\n"), -1)
	p := newParser(src)
	return p.Parse()
}
var errEofToken = errors.New("EOF token found")
func (p *Parser) Parse() (*ast.File, error) {
	f := &ast.File{}
	var err, scerr error
	p.sc.Error = func(pos token.Pos, msg string) {
		scerr = &PosError{Pos: pos, Err: errors.New(msg)}
	}
	f.Node, err = p.objectList(false)
	if scerr != nil {
		return nil, scerr
	}
	if err != nil {
		return nil, err
	}
	f.Comments = p.comments
	return f, nil
}
func (p *Parser) objectList(obj bool) (*ast.ObjectList, error) {
	defer un(trace(p, "ParseObjectList"))
	node := &ast.ObjectList{}
	for {
		if obj {
			tok := p.scan()
			p.unscan()
			if tok.Type == token.RBRACE {
				break
			}
		}
		n, err := p.objectItem()
		if err == errEofToken {
			break  
		}
		if err != nil {
			return node, err
		}
		node.Add(n)
		tok := p.scan()
		if tok.Type != token.COMMA {
			p.unscan()
		}
	}
	return node, nil
}
func (p *Parser) consumeComment() (comment *ast.Comment, endline int) {
	endline = p.tok.Pos.Line
	if len(p.tok.Text) > 1 && p.tok.Text[1] == '*' {
		for i := 0; i < len(p.tok.Text); i++ {
			if p.tok.Text[i] == '\n' {
				endline++
			}
		}
	}
	comment = &ast.Comment{Start: p.tok.Pos, Text: p.tok.Text}
	p.tok = p.sc.Scan()
	return
}
func (p *Parser) consumeCommentGroup(n int) (comments *ast.CommentGroup, endline int) {
	var list []*ast.Comment
	endline = p.tok.Pos.Line
	for p.tok.Type == token.COMMENT && p.tok.Pos.Line <= endline+n {
		var comment *ast.Comment
		comment, endline = p.consumeComment()
		list = append(list, comment)
	}
	comments = &ast.CommentGroup{List: list}
	p.comments = append(p.comments, comments)
	return
}
func (p *Parser) objectItem() (*ast.ObjectItem, error) {
	defer un(trace(p, "ParseObjectItem"))
	keys, err := p.objectKey()
	if len(keys) > 0 && err == errEofToken {
		err = nil
	}
	if len(keys) > 0 && err != nil && p.tok.Type == token.RBRACE {
		err = nil
		p.tok.Type = token.EOF
	}
	if err != nil {
		return nil, err
	}
	o := &ast.ObjectItem{
		Keys: keys,
	}
	if p.leadComment != nil {
		o.LeadComment = p.leadComment
		p.leadComment = nil
	}
	switch p.tok.Type {
	case token.ASSIGN:
		o.Assign = p.tok.Pos
		o.Val, err = p.object()
		if err != nil {
			return nil, err
		}
	case token.LBRACE:
		o.Val, err = p.objectType()
		if err != nil {
			return nil, err
		}
	default:
		keyStr := make([]string, 0, len(keys))
		for _, k := range keys {
			keyStr = append(keyStr, k.Token.Text)
		}
		return nil, &PosError{
			Pos: p.tok.Pos,
			Err: fmt.Errorf(
				"key '%s' expected start of object ('{') or assignment ('=')",
				strings.Join(keyStr, " ")),
		}
	}
	p.scan()
	if len(keys) > 0 && o.Val.Pos().Line == keys[0].Pos().Line && p.lineComment != nil {
		o.LineComment = p.lineComment
		p.lineComment = nil
	}
	p.unscan()
	return o, nil
}
func (p *Parser) objectKey() ([]*ast.ObjectKey, error) {
	keyCount := 0
	keys := make([]*ast.ObjectKey, 0)
	for {
		tok := p.scan()
		switch tok.Type {
		case token.EOF:
			return keys, errEofToken
		case token.ASSIGN:
			if keyCount > 1 {
				return nil, &PosError{
					Pos: p.tok.Pos,
					Err: fmt.Errorf("nested object expected: LBRACE got: %s", p.tok.Type),
				}
			}
			if keyCount == 0 {
				return nil, &PosError{
					Pos: p.tok.Pos,
					Err: errors.New("no object keys found!"),
				}
			}
			return keys, nil
		case token.LBRACE:
			var err error
			if len(keys) == 0 {
				err = &PosError{
					Pos: p.tok.Pos,
					Err: fmt.Errorf("expected: IDENT | STRING got: %s", p.tok.Type),
				}
			}
			return keys, err
		case token.IDENT, token.STRING:
			keyCount++
			keys = append(keys, &ast.ObjectKey{Token: p.tok})
		case token.ILLEGAL:
			return keys, &PosError{
				Pos: p.tok.Pos,
				Err: fmt.Errorf("illegal character"),
			}
		default:
			return keys, &PosError{
				Pos: p.tok.Pos,
				Err: fmt.Errorf("expected: IDENT | STRING | ASSIGN | LBRACE got: %s", p.tok.Type),
			}
		}
	}
}
func (p *Parser) object() (ast.Node, error) {
	defer un(trace(p, "ParseType"))
	tok := p.scan()
	switch tok.Type {
	case token.NUMBER, token.FLOAT, token.BOOL, token.STRING, token.HEREDOC:
		return p.literalType()
	case token.LBRACE:
		return p.objectType()
	case token.LBRACK:
		return p.listType()
	case token.COMMENT:
	case token.EOF:
		return nil, errEofToken
	}
	return nil, &PosError{
		Pos: tok.Pos,
		Err: fmt.Errorf("Unknown token: %+v", tok),
	}
}