parser: improve node parsing, remove string() and many other small fixes
This commit is contained in:
parent
45d01fe82d
commit
3832ed0981
@ -5,7 +5,6 @@ import "github.com/fatih/hcl/scanner"
|
|||||||
// Node is an element in the abstract syntax tree.
|
// Node is an element in the abstract syntax tree.
|
||||||
type Node interface {
|
type Node interface {
|
||||||
node()
|
node()
|
||||||
String() string
|
|
||||||
Pos() scanner.Pos
|
Pos() scanner.Pos
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,15 +27,6 @@ func (s *Source) add(node Node) {
|
|||||||
s.nodes = append(s.nodes, node)
|
s.nodes = append(s.nodes, node)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Source) String() string {
|
|
||||||
buf := ""
|
|
||||||
for _, n := range s.nodes {
|
|
||||||
buf += n.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Source) Pos() scanner.Pos {
|
func (s *Source) Pos() scanner.Pos {
|
||||||
// always returns the uninitiliazed position
|
// always returns the uninitiliazed position
|
||||||
return s.nodes[0].Pos()
|
return s.nodes[0].Pos()
|
||||||
@ -47,10 +37,6 @@ type Ident struct {
|
|||||||
token scanner.Token
|
token scanner.Token
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Ident) String() 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
|
||||||
}
|
}
|
||||||
@ -62,10 +48,6 @@ type AssignStatement struct {
|
|||||||
assign scanner.Pos // position of "="
|
assign scanner.Pos // position of "="
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AssignStatement) String() string {
|
|
||||||
return a.lhs.String() + " = " + a.rhs.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *AssignStatement) Pos() scanner.Pos {
|
func (a *AssignStatement) Pos() scanner.Pos {
|
||||||
return a.lhs.Pos()
|
return a.lhs.Pos()
|
||||||
}
|
}
|
||||||
@ -76,20 +58,6 @@ type ObjectStatement struct {
|
|||||||
ObjectType
|
ObjectType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ObjectStatement) String() string {
|
|
||||||
s := ""
|
|
||||||
|
|
||||||
for i, n := range o.Idents {
|
|
||||||
s += n.String()
|
|
||||||
if i != len(o.Idents) {
|
|
||||||
s += " "
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s += o.ObjectType.String()
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *ObjectStatement) Pos() scanner.Pos {
|
func (o *ObjectStatement) Pos() scanner.Pos {
|
||||||
return o.Idents[0].Pos()
|
return o.Idents[0].Pos()
|
||||||
}
|
}
|
||||||
@ -97,7 +65,7 @@ func (o *ObjectStatement) Pos() scanner.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 {
|
||||||
*Ident
|
token scanner.Token
|
||||||
}
|
}
|
||||||
|
|
||||||
// isValid() returns true if the underlying identifier satisfies one of the
|
// isValid() returns true if the underlying identifier satisfies one of the
|
||||||
@ -111,6 +79,10 @@ func (l *LiteralType) isValid() bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *LiteralType) Pos() scanner.Pos {
|
||||||
|
return l.token.Pos
|
||||||
|
}
|
||||||
|
|
||||||
// ListStatement represents a HCL List type
|
// ListStatement represents a HCL List type
|
||||||
type ListType struct {
|
type ListType struct {
|
||||||
lbrack scanner.Pos // position of "["
|
lbrack scanner.Pos // position of "["
|
||||||
@ -118,16 +90,6 @@ type ListType struct {
|
|||||||
list []Node // the elements in lexical order
|
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 {
|
func (l *ListType) Pos() scanner.Pos {
|
||||||
return l.lbrack
|
return l.lbrack
|
||||||
}
|
}
|
||||||
@ -139,16 +101,6 @@ type ObjectType struct {
|
|||||||
list []Node // the nodes in lexical order
|
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 {
|
func (b *ObjectType) Pos() scanner.Pos {
|
||||||
return b.lbrace
|
return b.lbrace
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,8 @@ func New(src []byte) *Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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"))
|
||||||
@ -31,16 +33,15 @@ func (p *Parser) Parse() (Node, error) {
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
n, err := p.parseNode()
|
n, err := p.parseNode()
|
||||||
|
if err == errEofToken {
|
||||||
|
break // we are finished
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we successfully parsed a node, add it to the final source node
|
||||||
node.add(n)
|
node.add(n)
|
||||||
|
|
||||||
// break if we hit the end
|
|
||||||
if p.tok.Type == scanner.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return node, nil
|
return node, nil
|
||||||
@ -50,24 +51,33 @@ func (p *Parser) parseNode() (Node, error) {
|
|||||||
defer un(trace(p, "ParseNode"))
|
defer un(trace(p, "ParseNode"))
|
||||||
|
|
||||||
tok := p.scan()
|
tok := p.scan()
|
||||||
|
|
||||||
fmt.Println(tok) // debug
|
fmt.Println(tok) // debug
|
||||||
|
|
||||||
if tok.Type.IsLiteral() {
|
switch tok.Type {
|
||||||
if p.prevTok.Type.IsLiteral() {
|
case scanner.ASSIGN:
|
||||||
|
return p.parseAssignment()
|
||||||
|
case scanner.LBRACK:
|
||||||
|
// return p.parseListType()
|
||||||
|
case scanner.LBRACE:
|
||||||
|
// return p.parseObjectTpe()
|
||||||
|
case scanner.COMMENT:
|
||||||
|
// implement comment
|
||||||
|
case scanner.EOF:
|
||||||
|
return nil, errEofToken
|
||||||
|
}
|
||||||
|
|
||||||
|
if tok.Type.IsIdentifier() {
|
||||||
|
if p.prevTok.Type.IsIdentifier() {
|
||||||
return p.parseObjectStatement()
|
return p.parseObjectStatement()
|
||||||
}
|
}
|
||||||
|
|
||||||
tok := p.scan()
|
if tok.Type.IsLiteral() {
|
||||||
if tok.Type == scanner.ASSIGN {
|
return p.parseLiteralType()
|
||||||
return p.parseAssignment()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p.unscan()
|
|
||||||
return p.parseIdent()
|
return p.parseIdent()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New("not yet implemented")
|
return nil, fmt.Errorf("not yet implemented: %s", tok.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseAssignment parses an assignment and returns a AssignStatement AST
|
// parseAssignment parses an assignment and returns a AssignStatement AST
|
||||||
@ -93,10 +103,6 @@ func (p *Parser) parseAssignment() (*AssignStatement, error) {
|
|||||||
func (p *Parser) parseIdent() (*Ident, error) {
|
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
|
}, nil
|
||||||
@ -104,24 +110,18 @@ func (p *Parser) parseIdent() (*Ident, error) {
|
|||||||
|
|
||||||
// parseLiteralType parses a literal type and returns a LiteralType AST
|
// parseLiteralType parses a literal type and returns a LiteralType AST
|
||||||
func (p *Parser) parseLiteralType() (*LiteralType, error) {
|
func (p *Parser) parseLiteralType() (*LiteralType, error) {
|
||||||
i, err := p.parseIdent()
|
defer un(trace(p, "ParseLiteral"))
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
l := &LiteralType{}
|
return &LiteralType{
|
||||||
l.Ident = i
|
token: p.tok,
|
||||||
|
}, nil
|
||||||
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
|
// parseObjectStatement parses an object statement returns an ObjectStatement
|
||||||
// AST. ObjectsStatements represents both normal and nested objects statement
|
// AST. ObjectsStatements represents both normal and nested objects statement
|
||||||
func (p *Parser) parseObjectStatement() (*ObjectStatement, error) {
|
func (p *Parser) parseObjectStatement() (*ObjectStatement, error) {
|
||||||
|
defer un(trace(p, "ParseObjectStatement"))
|
||||||
|
|
||||||
return nil, errors.New("ObjectStatement is not implemented yet")
|
return nil, errors.New("ObjectStatement is not implemented yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,12 +11,7 @@ func TestAssignStatement(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.String() != src {
|
|
||||||
t.Errorf("AssignStatement is not parsed correctly\n\twant: '%s'\n\tgot : '%s'", src, n.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,13 +21,15 @@ const (
|
|||||||
EOF
|
EOF
|
||||||
COMMENT
|
COMMENT
|
||||||
|
|
||||||
|
identifier_beg
|
||||||
|
IDENT // literals
|
||||||
literal_beg
|
literal_beg
|
||||||
IDENT // literals
|
|
||||||
NUMBER // 12345
|
NUMBER // 12345
|
||||||
FLOAT // 123.45
|
FLOAT // 123.45
|
||||||
BOOL // true,false
|
BOOL // true,false
|
||||||
STRING // "abc"
|
STRING // "abc"
|
||||||
literal_end
|
literal_end
|
||||||
|
identifier_end
|
||||||
|
|
||||||
operator_beg
|
operator_beg
|
||||||
LBRACK // [
|
LBRACK // [
|
||||||
@ -81,8 +83,12 @@ func (t TokenType) String() string {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsLiteral returns true for tokens corresponding to identifiers and basic
|
// IsIdentifier returns true for tokens corresponding to identifiers and basic
|
||||||
// type literals; it returns false otherwise.
|
// type literals; it returns false otherwise.
|
||||||
|
func (t TokenType) IsIdentifier() bool { return identifier_beg < t && t < identifier_end }
|
||||||
|
|
||||||
|
// IsLiteral returns true for tokens corresponding to basic type literals; it
|
||||||
|
// returns false otherwise.
|
||||||
func (t TokenType) IsLiteral() bool { return literal_beg < t && t < literal_end }
|
func (t TokenType) IsLiteral() bool { return literal_beg < t && t < literal_end }
|
||||||
|
|
||||||
// IsOperator returns true for tokens corresponding to operators and
|
// IsOperator returns true for tokens corresponding to operators and
|
||||||
|
Loading…
Reference in New Issue
Block a user