1// Copyright 2011 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Parse nodes.
6package parse
7
8import "fmt"
9
10var textFormat = "%s" // Changed to "%q" in tests for better error messages.
11
12// A Node is an element in the parse tree. The interface is trivial.
13// The interface contains an unexported method so that only
14// types local to this package can satisfy it.
15type Node interface {
16	Type() NodeType
17	String() string
18	Position() Pos // byte position of start of node in full original input string
19	// Make sure only functions in this package can create Nodes.
20	unexported()
21}
22
23// NodeType identifies the type of a parse tree node.
24type NodeType int
25
26// Pos represents a byte position in the original input text from which
27// this template was parsed.
28type Pos int
29
30func (p Pos) Position() Pos {
31	return p
32}
33
34// unexported keeps Node implementations local to the package.
35// All implementations embed Pos, so this takes care of it.
36func (Pos) unexported() {
37}
38
39// Type returns itself and provides an easy default implementation
40// for embedding in a Node. Embedded in all non-trivial Nodes.
41func (t NodeType) Type() NodeType {
42	return t
43}
44
45const (
46	NodeAsk    NodeType = iota // key:value expression.
47	NodeBinary NodeType = iota //
48	NodeUnary  NodeType = iota //
49)
50
51// BinaryNode holds two arguments and an operator.
52type BinaryNode struct {
53	NodeType
54	Pos
55	Args     [2]Node
56	Operator item
57	OpStr    string
58}
59
60func newBinary(operator item, arg1, arg2 Node) *BinaryNode {
61	return &BinaryNode{NodeType: NodeBinary, Pos: operator.pos, Args: [2]Node{arg1, arg2}, Operator: operator, OpStr: operator.val}
62}
63
64func (b *BinaryNode) String() string {
65	return fmt.Sprintf("%s %s %s", b.Args[0], b.Operator.val, b.Args[1])
66}
67
68func (b *BinaryNode) StringAST() string {
69	return fmt.Sprintf("%s(%s, %s)", b.Operator.val, b.Args[0], b.Args[1])
70}
71
72// UnaryNode holds one argument and an operator.
73type UnaryNode struct {
74	NodeType
75	Pos
76	Arg      Node
77	Operator item
78	OpStr    string
79}
80
81func newUnary(operator item, arg Node) *UnaryNode {
82	return &UnaryNode{NodeType: NodeUnary, Pos: operator.pos, Arg: arg, Operator: operator, OpStr: operator.val}
83}
84
85func (u *UnaryNode) String() string {
86	return fmt.Sprintf("%s%s", u.Operator.val, u.Arg)
87}
88
89func (u *UnaryNode) StringAST() string {
90	return fmt.Sprintf("%s(%s)", u.Operator.val, u.Arg)
91}
92
93// Walk invokes f on n and sub-nodes of n.
94func Walk(n Node, f func(Node)) {
95	f(n)
96	switch n := n.(type) {
97	case *BinaryNode:
98		Walk(n.Args[0], f)
99		Walk(n.Args[1], f)
100	case *AskNode:
101		// Ignore.
102	case *UnaryNode:
103		Walk(n.Arg, f)
104	default:
105		panic(fmt.Errorf("other type: %T", n))
106	}
107}
108
109// AskNode holds a filter invocation.
110type AskNode struct {
111	NodeType
112	Pos
113	Text string
114}
115
116func (a *AskNode) String() string {
117	return fmt.Sprintf("%s", a.Text)
118}
119
120func newAsk(pos Pos, text string) *AskNode {
121	return &AskNode{
122		NodeType: NodeAsk,
123		Pos:      pos,
124		Text:     text,
125	}
126}