parser: assignments and objects are actually items and the same
This commit is contained in:
parent
3832ed0981
commit
62caacf06f
@ -8,28 +8,48 @@ type Node interface {
|
||||
Pos() scanner.Pos
|
||||
}
|
||||
|
||||
func (Source) node() {}
|
||||
func (Ident) node() {}
|
||||
|
||||
func (AssignStatement) node() {}
|
||||
func (ObjectStatement) node() {}
|
||||
|
||||
func (LiteralType) node() {}
|
||||
func (ObjectList) node() {}
|
||||
func (ObjectItem) node() {}
|
||||
func (ObjectType) node() {}
|
||||
func (LiteralType) node() {}
|
||||
func (ListType) node() {}
|
||||
func (Ident) node() {}
|
||||
|
||||
// Source represents a single HCL source file
|
||||
type Source struct {
|
||||
nodes []Node
|
||||
// ObjectList represents a list of ObjectItems. An HCL file itself is an
|
||||
// ObjectList.
|
||||
type ObjectList struct {
|
||||
items []*ObjectItem
|
||||
}
|
||||
|
||||
func (s *Source) add(node Node) {
|
||||
s.nodes = append(s.nodes, node)
|
||||
func (o *ObjectList) add(item *ObjectItem) {
|
||||
o.items = append(o.items, item)
|
||||
}
|
||||
|
||||
func (s *Source) Pos() scanner.Pos {
|
||||
func (o *ObjectList) Pos() scanner.Pos {
|
||||
// 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.
|
||||
@ -41,27 +61,6 @@ func (i *Ident) Pos() scanner.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:
|
||||
// scanner.NUMBER, scanner.FLOAT, scanner.BOOL and scanner.STRING
|
||||
type LiteralType struct {
|
||||
|
@ -29,10 +29,10 @@ var errEofToken = errors.New("EOF token found")
|
||||
// Parse returns the fully parsed source and returns the abstract syntax tree.
|
||||
func (p *Parser) Parse() (Node, error) {
|
||||
defer un(trace(p, "ParseSource"))
|
||||
node := &Source{}
|
||||
node := &ObjectList{}
|
||||
|
||||
for {
|
||||
n, err := p.parseNode()
|
||||
n, err := p.parseObjectItem()
|
||||
if err == errEofToken {
|
||||
break // we are finished
|
||||
}
|
||||
@ -47,15 +47,15 @@ func (p *Parser) Parse() (Node, error) {
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func (p *Parser) parseNode() (Node, error) {
|
||||
defer un(trace(p, "ParseNode"))
|
||||
func (p *Parser) parseObjectItem() (*ObjectItem, error) {
|
||||
defer un(trace(p, "ParseObjectItem"))
|
||||
|
||||
tok := p.scan()
|
||||
fmt.Println(tok) // debug
|
||||
|
||||
switch tok.Type {
|
||||
case scanner.ASSIGN:
|
||||
return p.parseAssignment()
|
||||
// return p.parseAssignment()
|
||||
case scanner.LBRACK:
|
||||
// return p.parseListType()
|
||||
case scanner.LBRACE:
|
||||
@ -66,39 +66,9 @@ func (p *Parser) parseNode() (Node, error) {
|
||||
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)
|
||||
}
|
||||
|
||||
// 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
|
||||
func (p *Parser) parseIdent() (*Ident, error) {
|
||||
defer un(trace(p, "ParseIdent"))
|
||||
@ -117,14 +87,6 @@ func (p *Parser) parseLiteralType() (*LiteralType, error) {
|
||||
}, 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
|
||||
func (p *Parser) parseObjectType() (*ObjectType, error) {
|
||||
return nil, errors.New("ObjectType is not implemented yet")
|
||||
|
@ -1,6 +1,9 @@
|
||||
package parser
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAssignStatement(t *testing.T) {
|
||||
src := `ami = "${var.foo}"`
|
||||
@ -14,4 +17,13 @@ func TestAssignStatement(t *testing.T) {
|
||||
if n.Pos().Line != 1 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user