parser: imrprovements to AST types

This commit is contained in:
Fatih Arslan 2015-10-12 22:53:40 +03:00
parent 0a3fe0e81e
commit 8d60ae5dc5
4 changed files with 107 additions and 68 deletions

View File

@ -21,13 +21,16 @@ type Node interface {
Pos() scanner.Pos
}
func (Source) node() {}
func (Ident) node() {}
func (BlockStatement) node() {}
func (Source) node() {}
func (Ident) node() {}
func (AssignStatement) node() {}
func (ListStatement) node() {}
func (ObjectStatement) node() {}
func (LiteralType) node() {}
func (ObjectType) node() {}
func (ListType) node() {}
// Source represents a single HCL source file
type Source struct {
nodes []Node
@ -57,33 +60,13 @@ type Ident struct {
}
func (i *Ident) String() string {
return i.token.String()
return i.token.Text
}
func (i *Ident) Pos() scanner.Pos {
return i.token.Pos
}
type BlockStatement struct {
lbrace scanner.Pos // position of "{"
rbrace scanner.Pos // position of "}"
list []Node // the nodes in lexical order
}
func (b *BlockStatement) String() string {
s := "{\n"
for _, n := range b.list {
s += n.String() + "\n"
}
s += "}"
return s
}
func (b *BlockStatement) Pos() scanner.Pos {
return b.lbrace
}
// AssignStatement represents an assignment
type AssignStatement struct {
lhs Node // left hand side of the assignment
@ -99,31 +82,10 @@ func (a *AssignStatement) Pos() scanner.Pos {
return a.lhs.Pos()
}
// ListStatement represents a list
type ListStatement struct {
lbrack scanner.Pos // position of "["
rbrack scanner.Pos // position of "]"
list []Node // the elements in lexical order
}
func (l *ListStatement) String() string {
s := "[\n"
for _, n := range l.list {
s += n.String() + ",\n"
}
s += "]"
return s
}
func (l *ListStatement) Pos() scanner.Pos {
return l.lbrack
}
// ObjectStatment represents an object
// ObjectStatment represents an object statement
type ObjectStatement struct {
Idents []Node // the idents in elements in lexical order
BlockStatement
ObjectType
}
func (o *ObjectStatement) String() string {
@ -136,10 +98,66 @@ func (o *ObjectStatement) String() string {
}
}
s += o.BlockStatement.String()
s += o.ObjectType.String()
return s
}
func (o *ObjectStatement) Pos() scanner.Pos {
return o.Idents[0].Pos()
}
// LiteralType represents a literal of basic type. Valid types are:
// scanner.NUMBER, scanner.FLOAT, scanner.BOOL and scanner.STRING
type LiteralType struct {
token scanner.Token
}
func (l *LiteralType) String() string {
return l.token.Text
}
func (l *LiteralType) Pos() scanner.Pos {
return l.token.Pos
}
// ListStatement represents a HCL List type
type ListType struct {
lbrack scanner.Pos // position of "["
rbrack scanner.Pos // position of "]"
list []Node // the elements in lexical order
}
func (l *ListType) String() string {
s := "[\n"
for _, n := range l.list {
s += n.String() + ",\n"
}
s += "]"
return s
}
func (l *ListType) Pos() scanner.Pos {
return l.lbrack
}
// ObjectType represents a HCL Object Type
type ObjectType struct {
lbrace scanner.Pos // position of "{"
rbrace scanner.Pos // position of "}"
list []Node // the nodes in lexical order
}
func (b *ObjectType) String() string {
s := "{\n"
for _, n := range b.list {
s += n.String() + "\n"
}
s += "}"
return s
}
func (b *ObjectType) Pos() scanner.Pos {
return b.lbrace
}

View File

@ -1,6 +1,7 @@
package parser
import (
"errors"
"fmt"
"github.com/fatih/hcl/scanner"
@ -29,10 +30,13 @@ func (p *Parser) Parse() (Node, error) {
node := &Source{}
for {
if n := p.parseStatement(); n != nil {
node.add(n)
n, err := p.parseNode()
if err != nil {
return nil, err
}
node.add(n)
// break if we hit the end
if p.tok.Type == scanner.EOF {
break
@ -42,17 +46,20 @@ func (p *Parser) Parse() (Node, error) {
return node, nil
}
func (p *Parser) parseStatement() Node {
defer un(trace(p, "ParseStatement"))
func (p *Parser) parseNode() (Node, error) {
defer un(trace(p, "ParseNode"))
tok := p.scan()
fmt.Println(tok) // debug
if tok.Type.IsLiteral() {
if p.prevTok.Type.IsLiteral() {
return p.parseObject()
return p.parseObjectType()
}
if tok := p.scan(); tok.Type == scanner.ASSIGN {
tok := p.scan()
if tok.Type == scanner.ASSIGN {
return p.parseAssignment()
}
@ -60,34 +67,45 @@ func (p *Parser) parseStatement() Node {
return p.parseIdent()
}
return nil
return nil, errors.New("not yet implemented")
}
func (p *Parser) parseAssignment() Node {
func (p *Parser) parseAssignment() (*AssignStatement, error) {
defer un(trace(p, "ParseAssignment"))
return &AssignStatement{
a := &AssignStatement{
lhs: &Ident{
token: p.prevTok,
},
assign: p.tok.Pos,
rhs: p.parseStatement(),
}
n, err := p.parseNode()
if err != nil {
return nil, err
}
a.rhs = n
return a, nil
}
func (p *Parser) parseIdent() Node {
func (p *Parser) parseIdent() (*Ident, error) {
defer un(trace(p, "ParseIdent"))
if !p.tok.Type.IsLiteral() {
return nil, errors.New("can't parse non literal token")
}
return &Ident{
token: p.tok,
}
}, nil
}
func (p *Parser) parseObject() Node {
return nil
func (p *Parser) parseObjectType() (*ObjectStatement, error) {
return nil, errors.New("ObjectStatement is not implemented yet")
}
func (p *Parser) parseList() Node {
return nil
func (p *Parser) parseListType() (*ListType, error) {
return nil, errors.New("ListStatement is not implemented yet")
}
// scan returns the next token from the underlying scanner.

View File

@ -2,7 +2,7 @@ package parser
import "testing"
func TestAssignStatment(t *testing.T) {
func TestAssignStatement(t *testing.T) {
src := `ami = "${var.foo}"`
p := New([]byte(src))
p.enableTrace = true

View File

@ -1,6 +1,9 @@
package scanner
import "strconv"
import (
"fmt"
"strconv"
)
// Token defines a single HCL token which can be obtained via the Scanner
type Token struct {
@ -90,5 +93,5 @@ func (t TokenType) IsOperator() bool { return operator_beg < t && t < operator_e
// applicable for certain token types, such as token.IDENT,
// token.STRING, etc..
func (t Token) String() string {
return t.Text
return fmt.Sprintf("%s %s %s", t.Pos.String(), t.Type.String(), t.Text)
}