2015-10-03 11:32:19 +00:00
|
|
|
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 {
|
2015-10-11 22:38:59 +00:00
|
|
|
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{
|
2015-10-11 21:20:17 +00:00
|
|
|
sc: scanner.New(src),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-11 22:38:59 +00:00
|
|
|
// 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 != nil {
|
|
|
|
return nil, err
|
2015-10-11 23:49:07 +00:00
|
|
|
}
|
|
|
|
|
2015-10-12 19:53:40 +00:00
|
|
|
node.add(n)
|
|
|
|
|
2015-10-11 23:27:43 +00:00
|
|
|
// break if we hit the end
|
|
|
|
if p.tok.Type == scanner.EOF {
|
|
|
|
break
|
|
|
|
}
|
2015-10-07 22:38:39 +00:00
|
|
|
}
|
2015-10-11 21:20:17 +00:00
|
|
|
|
2015-10-12 07:37:37 +00:00
|
|
|
return node, nil
|
2015-10-11 22:38:59 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2015-10-11 22:38:59 +00:00
|
|
|
tok := p.scan()
|
|
|
|
|
2015-10-12 19:53:40 +00:00
|
|
|
fmt.Println(tok) // debug
|
|
|
|
|
2015-10-11 23:27:43 +00:00
|
|
|
if tok.Type.IsLiteral() {
|
|
|
|
if p.prevTok.Type.IsLiteral() {
|
2015-10-12 20:44:53 +00:00
|
|
|
return p.parseObjectStatement()
|
2015-10-11 23:27:43 +00:00
|
|
|
}
|
2015-10-11 22:38:59 +00:00
|
|
|
|
2015-10-12 19:53:40 +00:00
|
|
|
tok := p.scan()
|
|
|
|
if tok.Type == scanner.ASSIGN {
|
2015-10-11 23:49:07 +00:00
|
|
|
return p.parseAssignment()
|
|
|
|
}
|
|
|
|
|
|
|
|
p.unscan()
|
|
|
|
return p.parseIdent()
|
2015-10-11 22:38:59 +00:00
|
|
|
}
|
2015-10-11 23:27:43 +00:00
|
|
|
|
2015-10-12 19:53:40 +00:00
|
|
|
return nil, errors.New("not yet implemented")
|
2015-10-11 22:38:59 +00:00
|
|
|
}
|
|
|
|
|
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-12 19:53:40 +00:00
|
|
|
if !p.tok.Type.IsLiteral() {
|
|
|
|
return nil, errors.New("can't parse non literal token")
|
|
|
|
}
|
|
|
|
|
2015-10-11 23:28:27 +00:00
|
|
|
return &Ident{
|
2015-10-11 22:38:59 +00:00
|
|
|
token: p.tok,
|
2015-10-12 19:53:40 +00:00
|
|
|
}, nil
|
2015-10-11 22:38:59 +00:00
|
|
|
}
|
|
|
|
|
2015-10-12 20:44:53 +00:00
|
|
|
// parseLiteralType parses a literal type and returns a LiteralType AST
|
|
|
|
func (p *Parser) parseLiteralType() (*LiteralType, error) {
|
|
|
|
i, err := p.parseIdent()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
l := &LiteralType{}
|
|
|
|
l.Ident = i
|
|
|
|
|
|
|
|
if !l.isValid() {
|
|
|
|
return nil, fmt.Errorf("Identifier is not a LiteralType: %s", l.token)
|
|
|
|
}
|
|
|
|
|
|
|
|
return l, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// parseObjectStatement parses an object statement returns an ObjectStatement
|
|
|
|
// AST. ObjectsStatements represents both normal and nested objects statement
|
|
|
|
func (p *Parser) parseObjectStatement() (*ObjectStatement, error) {
|
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")
|
2015-10-11 22:38:59 +00:00
|
|
|
}
|
|
|
|
|
2015-10-11 21:20:17 +00:00
|
|
|
// 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.
|
2015-10-11 22:38:59 +00:00
|
|
|
if p.n != 0 {
|
|
|
|
p.n = 0
|
|
|
|
return p.tok
|
2015-10-11 21:20:17 +00:00
|
|
|
}
|
|
|
|
|
2015-10-11 22:38:59 +00:00
|
|
|
// store previous token
|
|
|
|
p.prevTok = p.tok
|
|
|
|
|
2015-10-11 21:20:17 +00:00
|
|
|
// Otherwise read the next token from the scanner and Save it to the buffer
|
|
|
|
// in case we unscan later.
|
2015-10-11 22:38:59 +00:00
|
|
|
p.tok = p.sc.Scan()
|
|
|
|
return p.tok
|
2015-10-07 22:38:39 +00:00
|
|
|
}
|
2015-10-11 21:20:17 +00:00
|
|
|
|
|
|
|
// unscan pushes the previously read token back onto the buffer.
|
2015-10-11 23:49:07 +00:00
|
|
|
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(")")
|
|
|
|
}
|