fx/node.go

249 lines
4.1 KiB
Go
Raw Normal View History

2023-09-07 23:53:51 +03:00
package main
2023-09-12 14:06:48 +03:00
import (
"strconv"
2023-09-24 16:01:39 +03:00
jsonpath "github.com/antonmedv/fx/path"
2023-09-12 14:06:48 +03:00
)
2023-09-07 23:53:51 +03:00
type node struct {
prev, next, end *node
2023-09-08 13:05:44 +03:00
directParent *node
indirectParent *node
collapsed *node
2023-09-07 23:53:51 +03:00
depth uint8
key []byte
value []byte
2023-09-11 14:16:10 +03:00
chunk []byte
2023-09-15 00:47:30 +03:00
chunkEnd *node
2023-09-07 23:53:51 +03:00
comma bool
2023-09-11 19:27:54 +03:00
index int
2023-09-07 23:53:51 +03:00
}
// append ands a node as a child to the current node (body of {...} or [...]).
2023-09-10 17:12:38 +03:00
func (n *node) append(child *node) {
if n.end == nil {
n.end = n
}
n.end.next = child
child.prev = n.end
if child.end == nil {
n.end = child
} else {
n.end = child.end
}
}
// adjacent adds a node as a sibling to the current node ({}{}{} or [][][]).
func (n *node) adjacent(child *node) {
end := n.end
if end == nil {
end = n
}
end.next = child
child.prev = end
}
2023-09-15 00:47:30 +03:00
func (n *node) insertChunk(chunk *node) {
if n.chunkEnd == nil {
n.insertAfter(chunk)
2023-09-11 14:16:10 +03:00
} else {
2023-09-15 00:47:30 +03:00
n.chunkEnd.insertAfter(chunk)
2023-09-11 14:16:10 +03:00
}
2023-09-15 00:47:30 +03:00
n.chunkEnd = chunk
2023-09-11 14:16:10 +03:00
}
func (n *node) insertAfter(child *node) {
if n.next == nil {
n.next = child
child.prev = n
} else {
old := n.next
n.next = child
child.prev = n
child.next = old
old.prev = child
}
}
func (n *node) dropChunks() {
2023-09-15 00:47:30 +03:00
if n.chunkEnd == nil {
2023-09-11 14:16:10 +03:00
return
}
n.chunk = nil
2023-09-15 00:47:30 +03:00
n.next = n.chunkEnd.next
2023-09-11 14:16:10 +03:00
if n.next != nil {
n.next.prev = n
}
2023-09-15 00:47:30 +03:00
n.chunkEnd = nil
2023-09-11 14:16:10 +03:00
}
2023-09-10 17:03:51 +03:00
func (n *node) hasChildren() bool {
return n.end != nil
}
2023-09-08 13:05:44 +03:00
func (n *node) parent() *node {
if n.directParent == nil {
return nil
}
parent := n.directParent
if parent.indirectParent != nil {
parent = parent.indirectParent
}
return parent
}
2023-09-10 17:12:38 +03:00
func (n *node) isCollapsed() bool {
return n.collapsed != nil
2023-09-07 23:53:51 +03:00
}
2023-09-08 12:14:48 +03:00
2023-09-09 01:14:46 +03:00
func (n *node) collapse() *node {
2023-09-10 17:11:42 +03:00
if n.end != nil && !n.isCollapsed() {
2023-09-08 13:05:44 +03:00
n.collapsed = n.next
2023-09-08 12:14:48 +03:00
n.next = n.end.next
if n.next != nil {
n.next.prev = n
}
2023-09-08 13:05:44 +03:00
}
2023-09-09 01:14:46 +03:00
return n
2023-09-08 13:05:44 +03:00
}
2023-09-11 18:50:38 +03:00
func (n *node) collapseRecursively() {
var at *node
if n.isCollapsed() {
at = n.collapsed
} else {
at = n.next
}
for at != nil && at != n.end {
if at.hasChildren() {
at.collapseRecursively()
at.collapse()
}
at = at.next
}
}
2023-09-08 13:05:44 +03:00
func (n *node) expand() {
2023-09-10 16:57:12 +03:00
if n.isCollapsed() {
if n.next != nil {
n.next.prev = n.end
}
2023-09-08 13:05:44 +03:00
n.next = n.collapsed
n.collapsed = nil
2023-09-08 12:14:48 +03:00
}
}
2023-09-11 18:50:38 +03:00
func (n *node) expandRecursively() {
at := n
for at != nil && at != n.end {
at.expand()
at = at.next
}
}
2023-09-12 14:06:48 +03:00
func (n *node) findChildByKey(key string) *node {
2023-09-15 10:56:11 +03:00
it := n.next
for it != nil && it != n.end {
if it.key != nil {
k, err := strconv.Unquote(string(it.key))
if err != nil {
return nil
}
if k == key {
return it
}
2023-09-12 14:06:48 +03:00
}
2023-09-15 10:56:11 +03:00
if it.chunkEnd != nil {
it = it.chunkEnd.next
} else if it.end != nil {
it = it.end.next
2023-09-12 14:06:48 +03:00
} else {
2023-09-15 10:56:11 +03:00
it = it.next
2023-09-12 14:06:48 +03:00
}
}
return nil
}
func (n *node) findChildByIndex(index int) *node {
for at := n.next; at != nil && at != n.end; {
if at.index == index {
return at
}
if at.end != nil {
at = at.end.next
} else {
at = at.next
}
}
return nil
}
2023-09-19 10:57:51 +03:00
func (n *node) paths(prefix string, paths *[]string, nodes *[]*node) {
it := n.next
for it != nil && it != n.end {
var path string
if it.key != nil {
quoted := string(it.key)
unquoted, err := strconv.Unquote(quoted)
2023-09-24 16:01:39 +03:00
if err == nil && jsonpath.Identifier.MatchString(unquoted) {
2023-09-19 10:57:51 +03:00
path = prefix + "." + unquoted
} else {
path = prefix + "[" + quoted + "]"
}
} else if it.index >= 0 {
path = prefix + "[" + strconv.Itoa(it.index) + "]"
}
*paths = append(*paths, path)
*nodes = append(*nodes, it)
if it.hasChildren() {
it.paths(path, paths, nodes)
it = it.end.next
} else {
it = it.next
}
}
}
func (n *node) children() ([]string, []*node) {
if !n.hasChildren() {
return nil, nil
}
var paths []string
var nodes []*node
var it *node
if n.isCollapsed() {
it = n.collapsed
} else {
it = n.next
}
for it != nil && it != n.end {
if it.key != nil {
2023-09-22 15:08:59 +03:00
key := string(it.key)
unquoted, err := strconv.Unquote(key)
if err == nil {
key = unquoted
2023-09-19 10:57:51 +03:00
}
2023-09-22 15:08:59 +03:00
paths = append(paths, key)
2023-09-19 10:57:51 +03:00
nodes = append(nodes, it)
}
if it.hasChildren() {
it = it.end.next
} else {
it = it.next
}
}
return paths, nodes
}