2019-02-26 13:05:15 +04:00
|
|
|
package jsonpath
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
|
|
|
|
func takeExponent(l lexer) error {
|
|
|
|
r := l.peek()
|
|
|
|
if r != 'e' && r != 'E' {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
l.take()
|
|
|
|
r = l.take()
|
|
|
|
switch r {
|
|
|
|
case '+', '-':
|
|
|
|
// Check digit immediately follows sign
|
|
|
|
if d := l.peek(); !(d >= '0' && d <= '9') {
|
2019-10-19 01:41:57 +04:00
|
|
|
return fmt.Errorf("expected digit after numeric sign instead of %#U", d)
|
2019-02-26 13:05:15 +04:00
|
|
|
}
|
|
|
|
takeDigits(l)
|
|
|
|
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
|
|
|
takeDigits(l)
|
|
|
|
default:
|
2019-10-19 01:41:57 +04:00
|
|
|
return fmt.Errorf("expected digit after 'e' instead of %#U", r)
|
2019-02-26 13:05:15 +04:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func takeJSONNumeric(l lexer) error {
|
|
|
|
cur := l.take()
|
|
|
|
switch cur {
|
|
|
|
case '-':
|
|
|
|
// Check digit immediately follows sign
|
|
|
|
if d := l.peek(); !(d >= '0' && d <= '9') {
|
2019-10-19 01:41:57 +04:00
|
|
|
return fmt.Errorf("expected digit after dash instead of %#U", d)
|
2019-02-26 13:05:15 +04:00
|
|
|
}
|
|
|
|
takeDigits(l)
|
|
|
|
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
|
|
|
takeDigits(l)
|
|
|
|
default:
|
2019-10-19 01:41:57 +04:00
|
|
|
return fmt.Errorf("expected digit or dash instead of %#U", cur)
|
2019-02-26 13:05:15 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// fraction or exponent
|
|
|
|
cur = l.peek()
|
|
|
|
switch cur {
|
|
|
|
case '.':
|
|
|
|
l.take()
|
|
|
|
// Check digit immediately follows period
|
|
|
|
if d := l.peek(); !(d >= '0' && d <= '9') {
|
2019-10-19 01:41:57 +04:00
|
|
|
return fmt.Errorf("expected digit after '.' instead of %#U", d)
|
2019-02-26 13:05:15 +04:00
|
|
|
}
|
|
|
|
takeDigits(l)
|
|
|
|
if err := takeExponent(l); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
case 'e', 'E':
|
|
|
|
if err := takeExponent(l); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func takeDigits(l lexer) {
|
|
|
|
for {
|
|
|
|
d := l.peek()
|
|
|
|
if d >= '0' && d <= '9' {
|
|
|
|
l.take()
|
|
|
|
} else {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only used at the very beginning of parsing. After that, the emit() function
|
|
|
|
// automatically skips whitespace.
|
|
|
|
func ignoreSpaceRun(l lexer) {
|
|
|
|
for {
|
|
|
|
r := l.peek()
|
|
|
|
if r == ' ' || r == '\t' || r == '\r' || r == '\n' {
|
|
|
|
l.take()
|
|
|
|
} else {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
l.ignore()
|
|
|
|
}
|
|
|
|
|
|
|
|
func takeExactSequence(l lexer, str []byte) bool {
|
|
|
|
for _, r := range str {
|
|
|
|
v := l.take()
|
|
|
|
if v != int(r) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func readerToArray(tr tokenReader) []Item {
|
|
|
|
vals := make([]Item, 0)
|
|
|
|
for {
|
|
|
|
i, ok := tr.next()
|
|
|
|
if !ok {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
v := *i
|
|
|
|
s := make([]byte, len(v.val))
|
|
|
|
copy(s, v.val)
|
|
|
|
v.val = s
|
|
|
|
vals = append(vals, v)
|
|
|
|
}
|
|
|
|
return vals
|
|
|
|
}
|
|
|
|
|
|
|
|
func findErrors(items []Item) (Item, bool) {
|
|
|
|
for _, i := range items {
|
|
|
|
if i.typ == lexError {
|
|
|
|
return i, true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Item{}, false
|
|
|
|
}
|
|
|
|
|
|
|
|
func byteSlicesEqual(a, b []byte) bool {
|
|
|
|
if len(a) != len(b) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := range a {
|
|
|
|
if a[i] != b[i] {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func firstError(errors ...error) error {
|
|
|
|
for _, e := range errors {
|
|
|
|
if e != nil {
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func abs(x int) int {
|
|
|
|
switch {
|
|
|
|
case x < 0:
|
|
|
|
return -x
|
|
|
|
case x == 0:
|
|
|
|
return 0 // return correctly abs(-0)
|
|
|
|
}
|
|
|
|
return x
|
|
|
|
}
|
|
|
|
|
|
|
|
//TODO: Kill the need for this
|
2019-10-19 01:41:57 +04:00
|
|
|
func getJSONTokenType(val []byte) (int, error) {
|
2019-02-26 13:05:15 +04:00
|
|
|
if len(val) == 0 {
|
2019-10-19 01:41:57 +04:00
|
|
|
return -1, errors.New("no value")
|
2019-02-26 13:05:15 +04:00
|
|
|
}
|
2019-10-19 01:41:57 +04:00
|
|
|
|
2019-02-26 13:05:15 +04:00
|
|
|
switch val[0] {
|
|
|
|
case '{':
|
|
|
|
return jsonBraceLeft, nil
|
|
|
|
case '"':
|
|
|
|
return jsonString, nil
|
|
|
|
case '[':
|
|
|
|
return jsonBracketLeft, nil
|
|
|
|
case 'n':
|
|
|
|
return jsonNull, nil
|
|
|
|
case 't', 'b':
|
|
|
|
return jsonBool, nil
|
|
|
|
case '-', '+', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
|
|
|
return jsonNumber, nil
|
|
|
|
default:
|
2019-10-19 01:41:57 +04:00
|
|
|
return -1, errors.New("unrecognized JSON value")
|
2019-02-26 13:05:15 +04:00
|
|
|
}
|
|
|
|
}
|