parser: assignments and objects are actually items and the same

This commit is contained in:
Fatih Arslan 2015-10-16 00:57:57 +03:00
parent 3832ed0981
commit 62caacf06f
3 changed files with 52 additions and 79 deletions

View File

@ -8,28 +8,48 @@ type Node interface {
Pos() scanner.Pos Pos() scanner.Pos
} }
func (Source) node() {} func (ObjectList) node() {}
func (Ident) node() {} func (ObjectItem) node() {}
func (AssignStatement) node() {}
func (ObjectStatement) node() {}
func (LiteralType) node() {}
func (ObjectType) node() {} func (ObjectType) node() {}
func (LiteralType) node() {}
func (ListType) node() {} func (ListType) node() {}
func (Ident) node() {}
// Source represents a single HCL source file // ObjectList represents a list of ObjectItems. An HCL file itself is an
type Source struct { // ObjectList.
nodes []Node type ObjectList struct {
items []*ObjectItem
} }
func (s *Source) add(node Node) { func (o *ObjectList) add(item *ObjectItem) {
s.nodes = append(s.nodes, node) o.items = append(o.items, item)
} }
func (s *Source) Pos() scanner.Pos { func (o *ObjectList) Pos() scanner.Pos {
// always returns the uninitiliazed position // always returns the uninitiliazed position
return s.nodes[0].Pos() return o.items[0].Pos()
}
// ObjectItem represents a HCL Object Item. An item is represented with a key
// (or keys). It can be an assignment or an object (both normal and nested)
type ObjectItem struct {
// key is either an Identifier or a String. The slice is only one lenght
// long, however if it's a nested object it'll can be larger than one. In
// that case "assign" is invalid as there is no assignments for a nested
// object.
key []Ident
// assign contains the position of "=", if any
assign scanner.Pos
// val is the item itself. It can be an object,list, number, bool or a
// string. If key lenght is larger than one, val can be only of type
// Object.
val Node
}
func (o *ObjectItem) Pos() scanner.Pos {
return o.key[0].Pos()
} }
// IdentStatement represents an identifier. // IdentStatement represents an identifier.
@ -41,27 +61,6 @@ func (i *Ident) Pos() scanner.Pos {
return i.token.Pos return i.token.Pos
} }
// AssignStatement represents an assignment
type AssignStatement struct {
lhs Node // left hand side of the assignment
rhs Node // right hand side of the assignment
assign scanner.Pos // position of "="
}
func (a *AssignStatement) Pos() scanner.Pos {
return a.lhs.Pos()
}
// ObjectStatment represents an object statement
type ObjectStatement struct {
Idents []Node // the idents in elements in lexical order
ObjectType
}
func (o *ObjectStatement) Pos() scanner.Pos {
return o.Idents[0].Pos()
}
// LiteralType represents a literal of basic type. Valid types are: // LiteralType represents a literal of basic type. Valid types are:
// scanner.NUMBER, scanner.FLOAT, scanner.BOOL and scanner.STRING // scanner.NUMBER, scanner.FLOAT, scanner.BOOL and scanner.STRING
type LiteralType struct { type LiteralType struct {

View File

@ -29,10 +29,10 @@ var errEofToken = errors.New("EOF token found")
// Parse returns the fully parsed source and returns the abstract syntax tree. // Parse returns the fully parsed source and returns the abstract syntax tree.
func (p *Parser) Parse() (Node, error) { func (p *Parser) Parse() (Node, error) {
defer un(trace(p, "ParseSource")) defer un(trace(p, "ParseSource"))
node := &Source{} node := &ObjectList{}
for { for {
n, err := p.parseNode() n, err := p.parseObjectItem()
if err == errEofToken { if err == errEofToken {
break // we are finished break // we are finished
} }
@ -47,15 +47,15 @@ func (p *Parser) Parse() (Node, error) {
return node, nil return node, nil
} }
func (p *Parser) parseNode() (Node, error) { func (p *Parser) parseObjectItem() (*ObjectItem, error) {
defer un(trace(p, "ParseNode")) defer un(trace(p, "ParseObjectItem"))
tok := p.scan() tok := p.scan()
fmt.Println(tok) // debug fmt.Println(tok) // debug
switch tok.Type { switch tok.Type {
case scanner.ASSIGN: case scanner.ASSIGN:
return p.parseAssignment() // return p.parseAssignment()
case scanner.LBRACK: case scanner.LBRACK:
// return p.parseListType() // return p.parseListType()
case scanner.LBRACE: case scanner.LBRACE:
@ -66,39 +66,9 @@ func (p *Parser) parseNode() (Node, error) {
return nil, errEofToken return nil, errEofToken
} }
if tok.Type.IsIdentifier() {
if p.prevTok.Type.IsIdentifier() {
return p.parseObjectStatement()
}
if tok.Type.IsLiteral() {
return p.parseLiteralType()
}
return p.parseIdent()
}
return nil, fmt.Errorf("not yet implemented: %s", tok.Type) return nil, fmt.Errorf("not yet implemented: %s", tok.Type)
} }
// parseAssignment parses an assignment and returns a AssignStatement AST
func (p *Parser) parseAssignment() (*AssignStatement, error) {
defer un(trace(p, "ParseAssignment"))
a := &AssignStatement{
lhs: &Ident{
token: p.prevTok,
},
assign: p.tok.Pos,
}
n, err := p.parseNode()
if err != nil {
return nil, err
}
a.rhs = n
return a, nil
}
// parseIdent parses a generic identifier and returns a Ident AST // parseIdent parses a generic identifier and returns a Ident AST
func (p *Parser) parseIdent() (*Ident, error) { func (p *Parser) parseIdent() (*Ident, error) {
defer un(trace(p, "ParseIdent")) defer un(trace(p, "ParseIdent"))
@ -117,14 +87,6 @@ func (p *Parser) parseLiteralType() (*LiteralType, error) {
}, nil }, nil
} }
// 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"))
return nil, errors.New("ObjectStatement is not implemented yet")
}
// parseObjectType parses an object type and returns a ObjectType AST // parseObjectType parses an object type and returns a ObjectType AST
func (p *Parser) parseObjectType() (*ObjectType, error) { func (p *Parser) parseObjectType() (*ObjectType, error) {
return nil, errors.New("ObjectType is not implemented yet") return nil, errors.New("ObjectType is not implemented yet")

View File

@ -1,6 +1,9 @@
package parser package parser
import "testing" import (
"fmt"
"testing"
)
func TestAssignStatement(t *testing.T) { func TestAssignStatement(t *testing.T) {
src := `ami = "${var.foo}"` src := `ami = "${var.foo}"`
@ -14,4 +17,13 @@ func TestAssignStatement(t *testing.T) {
if n.Pos().Line != 1 { if n.Pos().Line != 1 {
t.Errorf("AssignStatement position is wrong\n\twant: '%d'\n\tgot : '%d'", 1, n.Pos().Line) t.Errorf("AssignStatement position is wrong\n\twant: '%d'\n\tgot : '%d'", 1, n.Pos().Line)
} }
n1, ok := n.(*ObjectList)
if !ok {
t.Fatal("First Node should be of type Source")
}
for _, ns := range n1.nodes {
fmt.Printf("ns = %+v\n", ns)
}
} }