hcl/parser/parser.go

195 lines
4.1 KiB
Go
Raw Normal View History

package parser
2015-10-07 22:38:39 +00:00
2015-10-11 23:27:43 +00:00
import (
2015-10-12 19:53:40 +00:00
"errors"
2015-10-11 23:27:43 +00:00
"fmt"
"github.com/fatih/hcl/scanner"
)
2015-10-07 22:38:39 +00:00
type Parser struct {
sc *scanner.Scanner
tok scanner.Token // last read token
prevTok scanner.Token // previous read token
2015-10-11 23:27:43 +00:00
enableTrace bool
indent int
n int // buffer size (max = 1)
2015-10-07 22:38:39 +00:00
}
2015-10-11 23:27:43 +00:00
func New(src []byte) *Parser {
2015-10-07 22:38:39 +00:00
return &Parser{
sc: scanner.New(src),
}
}
var errEofToken = errors.New("EOF token found")
// Parse returns the fully parsed source and returns the abstract syntax tree.
2015-10-12 07:37:37 +00:00
func (p *Parser) Parse() (Node, error) {
2015-10-11 23:27:43 +00:00
defer un(trace(p, "ParseSource"))
node := &Source{}
for {
2015-10-12 19:53:40 +00:00
n, err := p.parseNode()
if err == errEofToken {
break // we are finished
}
2015-10-12 19:53:40 +00:00
if err != nil {
return nil, err
}
// we successfully parsed a node, add it to the final source node
2015-10-12 19:53:40 +00:00
node.add(n)
2015-10-07 22:38:39 +00:00
}
2015-10-12 07:37:37 +00:00
return node, nil
}
2015-10-12 19:53:40 +00:00
func (p *Parser) parseNode() (Node, error) {
defer un(trace(p, "ParseNode"))
2015-10-11 23:27:43 +00:00
tok := p.scan()
2015-10-12 19:53:40 +00:00
fmt.Println(tok) // debug
switch tok.Type {
case scanner.ASSIGN:
return p.parseAssignment()
case scanner.LBRACK:
// return p.parseListType()
case scanner.LBRACE:
// return p.parseObjectTpe()
case scanner.COMMENT:
// implement comment
case scanner.EOF:
return nil, errEofToken
}
if tok.Type.IsIdentifier() {
if p.prevTok.Type.IsIdentifier() {
2015-10-12 20:44:53 +00:00
return p.parseObjectStatement()
2015-10-11 23:27:43 +00:00
}
if tok.Type.IsLiteral() {
return p.parseLiteralType()
}
return p.parseIdent()
}
2015-10-11 23:27:43 +00:00
return nil, fmt.Errorf("not yet implemented: %s", tok.Type)
}
2015-10-12 20:44:53 +00:00
// parseAssignment parses an assignment and returns a AssignStatement AST
2015-10-12 19:53:40 +00:00
func (p *Parser) parseAssignment() (*AssignStatement, error) {
2015-10-11 23:27:43 +00:00
defer un(trace(p, "ParseAssignment"))
2015-10-12 19:53:40 +00:00
a := &AssignStatement{
2015-10-11 23:28:27 +00:00
lhs: &Ident{
2015-10-11 23:27:43 +00:00
token: p.prevTok,
},
assign: p.tok.Pos,
}
2015-10-12 19:53:40 +00:00
n, err := p.parseNode()
if err != nil {
return nil, err
}
a.rhs = n
return a, nil
2015-10-11 23:27:43 +00:00
}
2015-10-12 20:44:53 +00:00
// parseIdent parses a generic identifier and returns a Ident AST
2015-10-12 19:53:40 +00:00
func (p *Parser) parseIdent() (*Ident, error) {
2015-10-11 23:27:43 +00:00
defer un(trace(p, "ParseIdent"))
2015-10-11 23:28:27 +00:00
return &Ident{
token: p.tok,
2015-10-12 19:53:40 +00:00
}, nil
}
2015-10-12 20:44:53 +00:00
// parseLiteralType parses a literal type and returns a LiteralType AST
func (p *Parser) parseLiteralType() (*LiteralType, error) {
defer un(trace(p, "ParseLiteral"))
2015-10-12 20:44:53 +00:00
return &LiteralType{
token: p.tok,
}, nil
2015-10-12 20:44:53 +00:00
}
// parseObjectStatement parses an object statement returns an ObjectStatement
// AST. ObjectsStatements represents both normal and nested objects statement
func (p *Parser) parseObjectStatement() (*ObjectStatement, error) {
defer un(trace(p, "ParseObjectStatement"))
2015-10-12 19:53:40 +00:00
return nil, errors.New("ObjectStatement is not implemented yet")
2015-10-07 22:38:39 +00:00
}
2015-10-12 20:44:53 +00:00
// parseObjectType parses an object type and returns a ObjectType AST
func (p *Parser) parseObjectType() (*ObjectType, error) {
return nil, errors.New("ObjectType is not implemented yet")
}
// parseListType parses a list type and returns a ListType AST
2015-10-12 19:53:40 +00:00
func (p *Parser) parseListType() (*ListType, error) {
2015-10-12 20:44:53 +00:00
return nil, errors.New("ListType is not implemented yet")
}
// scan returns the next token from the underlying scanner.
// If a token has been unscanned then read that instead.
func (p *Parser) scan() scanner.Token {
// If we have a token on the buffer, then return it.
if p.n != 0 {
p.n = 0
return p.tok
}
// store previous token
p.prevTok = p.tok
// Otherwise read the next token from the scanner and Save it to the buffer
// in case we unscan later.
p.tok = p.sc.Scan()
return p.tok
2015-10-07 22:38:39 +00:00
}
// unscan pushes the previously read token back onto the buffer.
func (p *Parser) unscan() {
p.n = 1
p.tok = p.prevTok
}
2015-10-11 23:27:43 +00:00
// ----------------------------------------------------------------------------
// Parsing support
func (p *Parser) printTrace(a ...interface{}) {
if !p.enableTrace {
return
}
const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
const n = len(dots)
fmt.Printf("%5d:%3d: ", p.tok.Pos.Line, p.tok.Pos.Column)
i := 2 * p.indent
for i > n {
fmt.Print(dots)
i -= n
}
// i <= n
fmt.Print(dots[0:i])
fmt.Println(a...)
}
func trace(p *Parser, msg string) *Parser {
p.printTrace(msg, "(")
p.indent++
return p
}
// Usage pattern: defer un(trace(p, "..."))
func un(p *Parser) {
p.indent--
p.printTrace(")")
}