Fix some parsing bugs, add tests for visitor pattern
This commit is contained in:
parent
0cffcbd1d0
commit
0aac9ca074
47
ast.go
47
ast.go
@ -1,5 +1,7 @@
|
||||
package hcl
|
||||
|
||||
// ValueType is an enum represnting the type of a value in
|
||||
// a LiteralNode.
|
||||
type ValueType byte
|
||||
|
||||
const (
|
||||
@ -8,23 +10,66 @@ const (
|
||||
ValueTypeString
|
||||
)
|
||||
|
||||
type Node interface{}
|
||||
// Node is implemented by all AST nodes for HCL.
|
||||
type Node interface {
|
||||
Accept(Visitor)
|
||||
}
|
||||
|
||||
// Visitor is the interface that must be implemented by any
|
||||
// structures who want to be visited as part of the visitor pattern
|
||||
// on the AST.
|
||||
type Visitor interface {
|
||||
Visit(Node)
|
||||
}
|
||||
|
||||
// ObjectNode represents an object that has multiple elements.
|
||||
// An object's elements may repeat (keys). This is expected to
|
||||
// be validated/removed at a semantic check, rather than at a
|
||||
// syntax level.
|
||||
type ObjectNode struct {
|
||||
Key string
|
||||
Elem []Node
|
||||
}
|
||||
|
||||
// AssignmentNode represents a direct assignment with an equals
|
||||
// sign.
|
||||
type AssignmentNode struct {
|
||||
Key string
|
||||
Value Node
|
||||
}
|
||||
|
||||
// ListNode represents a list or array of items.
|
||||
type ListNode struct {
|
||||
Elem []Node
|
||||
}
|
||||
|
||||
// LiteralNode is a direct value.
|
||||
type LiteralNode struct {
|
||||
Type ValueType
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
func (n ObjectNode) Accept(v Visitor) {
|
||||
for _, e := range n.Elem {
|
||||
e.Accept(v)
|
||||
}
|
||||
|
||||
v.Visit(n)
|
||||
}
|
||||
|
||||
func (n AssignmentNode) Accept(v Visitor) {
|
||||
n.Value.Accept(v)
|
||||
v.Visit(n)
|
||||
}
|
||||
|
||||
func (n ListNode) Accept(v Visitor) {
|
||||
for _, e := range n.Elem {
|
||||
e.Accept(v)
|
||||
}
|
||||
|
||||
v.Visit(n)
|
||||
}
|
||||
|
||||
func (n LiteralNode) Accept(v Visitor) {
|
||||
v.Visit(n)
|
||||
}
|
||||
|
70
ast_test.go
Normal file
70
ast_test.go
Normal file
@ -0,0 +1,70 @@
|
||||
package hcl
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAssignmentNode_accept(t *testing.T) {
|
||||
n := AssignmentNode{
|
||||
Key: "foo",
|
||||
Value: LiteralNode{Value: "foo"},
|
||||
}
|
||||
|
||||
expected := []Node{
|
||||
n.Value,
|
||||
n,
|
||||
}
|
||||
|
||||
v := new(MockVisitor)
|
||||
n.Accept(v)
|
||||
|
||||
if !reflect.DeepEqual(v.Nodes, expected) {
|
||||
t.Fatalf("bad: %#v", v.Nodes)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListNode_accept(t *testing.T) {
|
||||
n := ListNode{
|
||||
Elem: []Node{
|
||||
LiteralNode{Value: "foo"},
|
||||
LiteralNode{Value: "bar"},
|
||||
},
|
||||
}
|
||||
|
||||
expected := []Node{
|
||||
n.Elem[0],
|
||||
n.Elem[1],
|
||||
n,
|
||||
}
|
||||
|
||||
v := new(MockVisitor)
|
||||
n.Accept(v)
|
||||
|
||||
if !reflect.DeepEqual(v.Nodes, expected) {
|
||||
t.Fatalf("bad: %#v", v.Nodes)
|
||||
}
|
||||
}
|
||||
|
||||
func TestObjectNode_accept(t *testing.T) {
|
||||
n := ObjectNode{
|
||||
Key: "foo",
|
||||
Elem: []Node{
|
||||
LiteralNode{Value: "foo"},
|
||||
LiteralNode{Value: "bar"},
|
||||
},
|
||||
}
|
||||
|
||||
expected := []Node{
|
||||
n.Elem[0],
|
||||
n.Elem[1],
|
||||
n,
|
||||
}
|
||||
|
||||
v := new(MockVisitor)
|
||||
n.Accept(v)
|
||||
|
||||
if !reflect.DeepEqual(v.Nodes, expected) {
|
||||
t.Fatalf("bad: %#v", v.Nodes)
|
||||
}
|
||||
}
|
10
parse.y
10
parse.y
@ -134,11 +134,17 @@ listitem:
|
||||
}
|
||||
| NUMBER
|
||||
{
|
||||
$$ = $1
|
||||
$$ = LiteralNode{
|
||||
Type: ValueTypeInt,
|
||||
Value: $1,
|
||||
}
|
||||
}
|
||||
| STRING
|
||||
{
|
||||
$$ = $1
|
||||
$$ = LiteralNode{
|
||||
Type: ValueTypeString,
|
||||
Value: $1,
|
||||
}
|
||||
}
|
||||
|
||||
%%
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
func TestParse(t *testing.T) {
|
||||
cases := []struct {
|
||||
Name string
|
||||
Err bool
|
||||
Err bool
|
||||
}{
|
||||
{
|
||||
"comment.hcl",
|
||||
|
11
visitor_mock.go
Normal file
11
visitor_mock.go
Normal file
@ -0,0 +1,11 @@
|
||||
package hcl
|
||||
|
||||
// MockVisitor is a visitor implementation that can be used for tests
|
||||
// and simply records the nodes that it has visited.
|
||||
type MockVisitor struct {
|
||||
Nodes []Node
|
||||
}
|
||||
|
||||
func (v *MockVisitor) Visit(n Node) {
|
||||
v.Nodes = append(v.Nodes, n)
|
||||
}
|
Loading…
Reference in New Issue
Block a user