-
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathstack.go
More file actions
134 lines (112 loc) · 2.62 KB
/
stack.go
File metadata and controls
134 lines (112 loc) · 2.62 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
133
134
package helium
import "github.com/lestrrat-go/helium/internal/stack"
// nodeEntry is a lightweight record for the parser's element stack.
// It stores only the data needed for end-tag matching and SAX callbacks,
// avoiding a full *Element allocation per start tag.
type nodeEntry struct {
local string
prefix string
uri string
qname string
}
func (e *nodeEntry) Name() string {
return e.qname
}
func (e *nodeEntry) LocalName() string {
return e.local
}
func (e *nodeEntry) Prefix() string {
return e.prefix
}
func (e *nodeEntry) URI() string {
return e.uri
}
type nodeStack struct {
stack.Stack[nodeEntry]
}
type inputStack struct {
stack.Stack[any]
}
type nsStack struct {
stack.KeyedStack[nsStackItem]
}
type nsStackItem struct {
prefix string
href string
}
// Appease the sax.Namespace interface
func (i nsStackItem) Prefix() string {
return i.prefix
}
// Appease the sax.Namespace interface
func (i nsStackItem) URI() string {
return i.href
}
func (i nsStackItem) Key() string {
return i.prefix
}
func (s *nsStack) Push(prefix, uri string) {
// Force-append: namespace prefixes may be redeclared on child elements
// (shadowing the parent's binding), so we must allow duplicate keys.
// KeyedStack.Lookup searches from the end, giving correct shadowing.
s.KeyedStack = append(s.KeyedStack, nsStackItem{prefix: prefix, href: uri})
}
func (s *nsStack) Lookup(prefix string) string {
item, ok := s.KeyedStack.Lookup(prefix)
if !ok {
return ""
}
return item.href
}
// LookupInTopN searches only the top n entries of the stack for prefix.
// This is used to detect duplicate namespace declarations on the same
// element without being confused by ancestor bindings (which are valid
// prefix shadowing, not duplicates).
func (s *nsStack) LookupInTopN(prefix string, n int) string {
entries := s.Peek(n)
for i := len(entries) - 1; i >= 0; i-- {
if entries[i].prefix == prefix {
return entries[i].href
}
}
return ""
}
func (s *nodeStack) Push(e nodeEntry) {
s.Stack.Push(e)
}
func (s *nodeStack) Pop() *nodeEntry {
l := s.Peek(1)
if len(l) != 1 {
return nil
}
e := &l[0]
s.Stack.Pop()
return e
}
func (s *nodeStack) PeekOne() *nodeEntry {
l := s.Peek(1)
if len(l) != 1 {
return nil
}
return &l[0]
}
// the reason we're using any here is that we may have to
// push a ByteCursor or a RuneCursor, and they don't share
// a common API
func (s *inputStack) Push(c any) {
s.Stack.Push(c)
}
func (s *inputStack) Pop() any {
defer s.Stack.Pop()
if e := s.PeekOne(); e != nil {
return e
}
return nil
}
func (s *inputStack) PeekOne() any {
l := s.Peek(1)
if len(l) != 1 {
return nil
}
return l[0]
}