-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathnonterminal_node.go
More file actions
132 lines (111 loc) · 3.44 KB
/
nonterminal_node.go
File metadata and controls
132 lines (111 loc) · 3.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright (c) 2017 Opsidian Ltd.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package ast
import (
"fmt"
"github.com/conflowio/parsley/parsley"
)
// NonTerminalNode represents a branch node in the AST
type NonTerminalNode struct {
schema interface{}
token string
children []parsley.Node
pos parsley.Pos
readerPos parsley.Pos
interpreter parsley.Interpreter
}
// NewNonTerminalNode creates a new NonTerminalNode instance
func NewNonTerminalNode(token string, children []parsley.Node, interpreter parsley.Interpreter) *NonTerminalNode {
if len(children) == 0 {
panic("NewNonTerminalNode should not be called with empty node list")
}
for _, c := range children {
if c == nil {
panic("NewNonTerminalNode can not have children with nil values")
}
}
return &NonTerminalNode{
token: token,
children: children,
pos: children[0].Pos(),
readerPos: children[len(children)-1].ReaderPos(),
interpreter: interpreter,
}
}
// NewEmptyNonTerminalNode creates a new NonTerminalNode without children
func NewEmptyNonTerminalNode(token string, pos parsley.Pos, interpreter parsley.Interpreter) *NonTerminalNode {
return &NonTerminalNode{
token: token,
pos: pos,
readerPos: pos,
interpreter: interpreter,
}
}
// Token returns with the node token
func (n *NonTerminalNode) Token() string {
return n.token
}
// Schema returns the schema for the node's value
func (n *NonTerminalNode) Schema() interface{} {
return n.schema
}
// Value returns with the value of the node
func (n *NonTerminalNode) Value(userCtx interface{}) (interface{}, parsley.Error) {
if n.interpreter == nil {
panic("missing interpreter for node")
}
return n.interpreter.Eval(userCtx, n)
}
// Transform runs the given transformer on all children and returns the original node
func (n *NonTerminalNode) Transform(userCtx interface{}) (parsley.Node, parsley.Error) {
if n.interpreter != nil {
switch i := n.interpreter.(type) {
case parsley.NodeTransformer:
return i.TransformNode(userCtx, n)
}
}
var err parsley.Error
for i, child := range n.children {
if n.children[i], err = parsley.Transform(userCtx, child); err != nil {
return nil, err
}
}
return n, nil
}
// StaticCheck runs a static analysis if the interpreter has static analysis capabilities
func (n *NonTerminalNode) StaticCheck(userCtx interface{}) parsley.Error {
if n.interpreter != nil {
switch i := n.interpreter.(type) {
case parsley.StaticChecker:
schema, err := i.StaticCheck(userCtx, n)
if err != nil {
return err
}
n.schema = schema
}
}
return nil
}
// Pos returns the position
func (n *NonTerminalNode) Pos() parsley.Pos {
return n.pos
}
// Children returns with the children
func (n *NonTerminalNode) Children() []parsley.Node {
return n.children
}
// ReaderPos returns the position of the first character immediately after this node
func (n *NonTerminalNode) ReaderPos() parsley.Pos {
return n.readerPos
}
// SetReaderPos amends the reader position using the given function
func (n *NonTerminalNode) SetReaderPos(f func(parsley.Pos) parsley.Pos) {
n.readerPos = f(n.readerPos)
}
// String returns with a string representation of the node
func (n *NonTerminalNode) String() string {
return fmt.Sprintf("%s{%s, %d..%d}", n.token, n.children, n.pos, n.readerPos)
}