121 lines
2.0 KiB
Go
121 lines
2.0 KiB
Go
package parser
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type (
|
|
context struct {
|
|
exps []expectation
|
|
}
|
|
|
|
// Context building block
|
|
expectation struct {
|
|
typ expectationType
|
|
key string // Object key
|
|
index int64 // Array index
|
|
}
|
|
|
|
// Type of expectation: object or array
|
|
expectationType int
|
|
)
|
|
|
|
const (
|
|
unknown expectationType = iota
|
|
object
|
|
array
|
|
)
|
|
|
|
func (c *context) compare(c2 *context) bool {
|
|
if len(c.exps) != len(c2.exps) {
|
|
return false
|
|
}
|
|
|
|
for i, exp := range c.exps {
|
|
exp2 := c2.exps[i]
|
|
if exp.typ != exp2.typ {
|
|
return false
|
|
}
|
|
switch exp.typ {
|
|
case array:
|
|
if exp.index != -1 && exp2.index != -1 && exp.index != exp2.index {
|
|
return false
|
|
}
|
|
case object:
|
|
if exp.key != exp2.key {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (c *context) push(typ expectationType) {
|
|
c.exps = append(c.exps, expectation{
|
|
typ: typ,
|
|
})
|
|
}
|
|
|
|
func (c *context) pop() {
|
|
if len(c.exps) == 0 {
|
|
return
|
|
}
|
|
c.exps = c.exps[:len(c.exps)-1]
|
|
}
|
|
|
|
func (c *context) setKey(key string) {
|
|
c.exps[len(c.exps)-1].key = key
|
|
}
|
|
|
|
func (c *context) setIndex(i int64) {
|
|
c.exps[len(c.exps)-1].index = i
|
|
}
|
|
|
|
func parseSelectors(sels []string) map[string]*context {
|
|
ctxs := map[string]*context{}
|
|
for _, sel := range sels {
|
|
ctxs[sel] = &context{
|
|
exps: parseSelector(sel),
|
|
}
|
|
}
|
|
return ctxs
|
|
}
|
|
|
|
func parseSelector(sel string) []expectation {
|
|
exps := []expectation{}
|
|
parts := strings.Split(sel[1:], "/")
|
|
for _, part := range parts {
|
|
c := expectation{}
|
|
if len(part) > 2 && part[:1] == "[" && part[len(part)-1:] == "]" {
|
|
c.typ = array
|
|
part = part[1 : len(part)-1]
|
|
if part == "*" {
|
|
c.index = -1
|
|
} else if i, err := strconv.ParseInt(part, 10, 64); err == nil {
|
|
c.index = i
|
|
} else {
|
|
panic("Array index should be numeric: " + part)
|
|
}
|
|
} else {
|
|
c.typ = object
|
|
c.key = part
|
|
}
|
|
exps = append(exps, c)
|
|
}
|
|
|
|
return exps
|
|
}
|
|
|
|
func (e expectationType) String() string {
|
|
switch e {
|
|
case array:
|
|
return "Index"
|
|
case object:
|
|
return "Key"
|
|
default:
|
|
return "Unknown"
|
|
}
|
|
}
|