1
0
Fork 0
kifflom/parser/context.go

129 lines
2.1 KiB
Go

package parser
import (
"strconv"
"strings"
)
type (
context struct {
exps []expectation
}
// Context building block
expectation struct {
typ expectationType
greedy bool
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
}
if exp.greedy || exp2.greedy {
continue
}
switch exp.typ {
case array:
if 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.greedy = true
} 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
if part == "*" {
c.greedy = true
} else {
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"
}
}