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

@ -23,11 +23,14 @@ type Node interface {
func (Source) node() {} func (Source) node() {}
func (Ident) node() {} func (Ident) node() {}
func (BlockStatement) node() {}
func (AssignStatement) node() {} func (AssignStatement) node() {}
func (ListStatement) node() {}
func (ObjectStatement) node() {} func (ObjectStatement) node() {}
func (LiteralType) node() {}
func (ObjectType) node() {}
func (ListType) node() {}
// Source represents a single HCL source file // Source represents a single HCL source file
type Source struct { type Source struct {
nodes []Node nodes []Node
@ -57,33 +60,13 @@ type Ident struct {
} }
func (i *Ident) String() string { func (i *Ident) String() string {
return i.token.String() return i.token.Text
} }
func (i *Ident) Pos() scanner.Pos { func (i *Ident) Pos() scanner.Pos {
return i.token.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 // AssignStatement represents an assignment
type AssignStatement struct { type AssignStatement struct {
lhs Node // left hand side of the assignment lhs Node // left hand side of the assignment
@ -99,31 +82,10 @@ func (a *AssignStatement) Pos() scanner.Pos {
return a.lhs.Pos() return a.lhs.Pos()
} }
// ListStatement represents a list // ObjectStatment represents an object statement
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
type ObjectStatement struct { type ObjectStatement struct {
Idents []Node // the idents in elements in lexical order Idents []Node // the idents in elements in lexical order
BlockStatement ObjectType
} }
func (o *ObjectStatement) String() string { func (o *ObjectStatement) String() string {
@ -136,10 +98,66 @@ func (o *ObjectStatement) String() string {
} }
} }
s += o.BlockStatement.String() s += o.ObjectType.String()
return s return s
} }
func (o *ObjectStatement) Pos() scanner.Pos { func (o *ObjectStatement) Pos() scanner.Pos {
return o.Idents[0].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 package parser
import ( import (
"errors"
"fmt" "fmt"
"github.com/fatih/hcl/scanner" "github.com/fatih/hcl/scanner"
@ -29,10 +30,13 @@ func (p *Parser) Parse() (Node, error) {
node := &Source{} node := &Source{}
for { for {
if n := p.parseStatement(); n != nil { n, err := p.parseNode()
node.add(n) if err != nil {
return nil, err
} }
node.add(n)
// break if we hit the end // break if we hit the end
if p.tok.Type == scanner.EOF { if p.tok.Type == scanner.EOF {
break break
@ -42,17 +46,20 @@ func (p *Parser) Parse() (Node, error) {
return node, nil return node, nil
} }
func (p *Parser) parseStatement() Node { func (p *Parser) parseNode() (Node, error) {
defer un(trace(p, "ParseStatement")) defer un(trace(p, "ParseNode"))
tok := p.scan() tok := p.scan()
fmt.Println(tok) // debug
if tok.Type.IsLiteral() { if tok.Type.IsLiteral() {
if p.prevTok.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() return p.parseAssignment()
} }
@ -60,34 +67,45 @@ func (p *Parser) parseStatement() Node {
return p.parseIdent() 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")) defer un(trace(p, "ParseAssignment"))
return &AssignStatement{ a := &AssignStatement{
lhs: &Ident{ lhs: &Ident{
token: p.prevTok, token: p.prevTok,
}, },
assign: p.tok.Pos, 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")) defer un(trace(p, "ParseIdent"))
if !p.tok.Type.IsLiteral() {
return nil, errors.New("can't parse non literal token")
}
return &Ident{ return &Ident{
token: p.tok, token: p.tok,
} }, nil
} }
func (p *Parser) parseObject() Node { func (p *Parser) parseObjectType() (*ObjectStatement, error) {
return nil return nil, errors.New("ObjectStatement is not implemented yet")
} }
func (p *Parser) parseList() Node { func (p *Parser) parseListType() (*ListType, error) {
return nil return nil, errors.New("ListStatement is not implemented yet")
} }
// scan returns the next token from the underlying scanner. // scan returns the next token from the underlying scanner.

View File

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

View File

@ -1,6 +1,9 @@
package scanner package scanner
import "strconv" import (
"fmt"
"strconv"
)
// Token defines a single HCL token which can be obtained via the Scanner // Token defines a single HCL token which can be obtained via the Scanner
type Token struct { 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, // applicable for certain token types, such as token.IDENT,
// token.STRING, etc.. // token.STRING, etc..
func (t Token) String() string { func (t Token) String() string {
return t.Text return fmt.Sprintf("%s %s %s", t.Pos.String(), t.Type.String(), t.Text)
} }