-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoperations.go
133 lines (122 loc) · 2.94 KB
/
operations.go
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
package main
import (
"fmt"
"go-json/ast"
"regexp"
"strconv"
"strings"
)
func AstToString(node ast.Node, indentChar string) string {
var toString func(node ast.Node, tab int) string
toString = func(node ast.Node, tab int) string {
res := ""
switch node.(type) {
case ast.NumberNode:
n := node.(ast.NumberNode)
return n.Token.Value
case ast.StrNode:
n := node.(ast.StrNode)
return "\"" + n.Value + "\""
case ast.BoolNode:
n := node.(ast.BoolNode)
return n.Token.Value
case ast.NullNode:
n := node.(ast.NullNode)
return n.Token.Value
case ast.ObjectNode:
n := node.(ast.ObjectNode)
mapLength := len(n.Items)
i := 0
res += "{\n"
for key, value := range n.Items {
res += strings.Repeat(indentChar, tab+1) + "\"" + key + "\"" + ": "
res += toString(value, tab+1)
if i != mapLength-1 {
res += ","
}
res += "\n"
i += 1
}
res += strings.Repeat(indentChar, tab) + "}"
case ast.ArrayNode:
n := node.(ast.ArrayNode)
res += "[\n"
for i, item := range n.Items {
res += strings.Repeat(indentChar, tab+1) + toString(item, tab+1)
if i != len(n.Items)-1 {
res += ","
}
res += "\n"
}
res += strings.Repeat(indentChar, tab) + "]"
}
return res
}
return toString(node, 0)
}
func TraverseAst(node ast.Node) {
switch node.(type) {
case ast.NumberNode:
n := node.(ast.NumberNode)
fmt.Println(n.Value)
case ast.StrNode:
n := node.(ast.StrNode)
fmt.Println(n.Value)
case ast.BoolNode:
n := node.(ast.BoolNode)
fmt.Println(n.Value)
case ast.NullNode:
n := node.(ast.NullNode)
fmt.Println(n.Token.Value)
case ast.ObjectNode:
n := node.(ast.ObjectNode)
for _, value := range n.Items {
TraverseAst(value)
}
case ast.ArrayNode:
n := node.(ast.ArrayNode)
for _, item := range n.Items {
TraverseAst(item)
}
}
}
func Select(rootNode ast.Node, query string) (ast.Node, error) {
pattern := `^((\w+|\[\d+\])\.)*(\w+|\[\d+\])$`
matched, err := regexp.MatchString(pattern, query)
if err != nil {
return nil, err
}
if !matched {
return nil, fmt.Errorf("invalid query string: %v", query)
}
keys := strings.Split(query, ".")
currNode := rootNode
for _, q := range keys {
if q[0] != '[' {
node, ok := currNode.(ast.ObjectNode)
if !ok {
return nil, fmt.Errorf("invalid query: %v ; %v doesn't exist", query, q)
}
val, ok := node.Items[q]
if !ok {
return nil, fmt.Errorf("invalid query: %v ; key %v doesn't exist", query, q)
}
currNode = val
} else {
node, ok := currNode.(ast.ArrayNode)
if !ok {
return nil, fmt.Errorf("%v is not an array", q)
}
index, err := strconv.Atoi(q[1 : len(q)-1])
if err != nil {
return nil, fmt.Errorf("error converting integer to index: %v", err)
}
if index < 0 || index >= len(node.Items) {
return nil, fmt.Errorf("index %v out of range of %v", index, len(node.Items))
}
val := node.Items[index]
currNode = val
}
}
return currNode, nil
}