2019-02-26 13:05:15 +04:00
|
|
|
package jsonpath
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
|
|
|
|
func evalRoot(e *Eval, i *Item) evalStateFn {
|
|
|
|
switch i.typ {
|
|
|
|
case jsonBraceLeft:
|
|
|
|
e.levelStack.push(i.typ)
|
|
|
|
return evalObjectAfterOpen
|
|
|
|
case jsonBracketLeft:
|
|
|
|
e.levelStack.push(i.typ)
|
|
|
|
return evalArrayAfterOpen
|
|
|
|
case jsonError:
|
|
|
|
return evalError(e, i)
|
|
|
|
default:
|
|
|
|
e.Error = errors.New(UnexpectedToken)
|
|
|
|
}
|
2019-10-19 01:17:00 +04:00
|
|
|
|
2019-02-26 13:05:15 +04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func evalObjectAfterOpen(e *Eval, i *Item) evalStateFn {
|
|
|
|
switch i.typ {
|
|
|
|
case jsonKey:
|
|
|
|
c := i.val[1 : len(i.val)-1]
|
2019-10-19 01:17:00 +04:00
|
|
|
|
2019-02-26 13:05:15 +04:00
|
|
|
if e.copyValues {
|
|
|
|
d := make([]byte, len(c))
|
|
|
|
copy(d, c)
|
2019-10-19 01:17:00 +04:00
|
|
|
|
2019-02-26 13:05:15 +04:00
|
|
|
c = d
|
|
|
|
}
|
2019-10-19 01:17:00 +04:00
|
|
|
|
2019-02-26 13:05:15 +04:00
|
|
|
e.nextKey = c
|
2019-10-19 01:17:00 +04:00
|
|
|
|
2019-02-26 13:05:15 +04:00
|
|
|
return evalObjectColon
|
|
|
|
case jsonBraceRight:
|
|
|
|
return rightBraceOrBracket(e)
|
|
|
|
case jsonError:
|
|
|
|
return evalError(e, i)
|
|
|
|
default:
|
|
|
|
e.Error = errors.New(UnexpectedToken)
|
|
|
|
}
|
2019-10-19 01:17:00 +04:00
|
|
|
|
2019-02-26 13:05:15 +04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func evalObjectColon(e *Eval, i *Item) evalStateFn {
|
|
|
|
switch i.typ {
|
|
|
|
case jsonColon:
|
|
|
|
return evalObjectValue
|
|
|
|
case jsonError:
|
|
|
|
return evalError(e, i)
|
|
|
|
default:
|
|
|
|
e.Error = errors.New(UnexpectedToken)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func evalObjectValue(e *Eval, i *Item) evalStateFn {
|
|
|
|
e.location.push(e.nextKey)
|
|
|
|
|
|
|
|
switch i.typ {
|
|
|
|
case jsonNull, jsonNumber, jsonString, jsonBool:
|
|
|
|
return evalObjectAfterValue
|
|
|
|
case jsonBraceLeft:
|
|
|
|
e.levelStack.push(i.typ)
|
|
|
|
return evalObjectAfterOpen
|
|
|
|
case jsonBracketLeft:
|
|
|
|
e.levelStack.push(i.typ)
|
|
|
|
return evalArrayAfterOpen
|
|
|
|
case jsonError:
|
|
|
|
return evalError(e, i)
|
|
|
|
default:
|
|
|
|
e.Error = errors.New(UnexpectedToken)
|
|
|
|
}
|
2019-10-19 01:17:00 +04:00
|
|
|
|
2019-02-26 13:05:15 +04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func evalObjectAfterValue(e *Eval, i *Item) evalStateFn {
|
|
|
|
e.location.pop()
|
2019-10-19 01:17:00 +04:00
|
|
|
|
2019-02-26 13:05:15 +04:00
|
|
|
switch i.typ {
|
|
|
|
case jsonComma:
|
|
|
|
return evalObjectAfterOpen
|
|
|
|
case jsonBraceRight:
|
|
|
|
return rightBraceOrBracket(e)
|
|
|
|
case jsonError:
|
|
|
|
return evalError(e, i)
|
|
|
|
default:
|
|
|
|
e.Error = errors.New(UnexpectedToken)
|
|
|
|
}
|
2019-10-19 01:17:00 +04:00
|
|
|
|
2019-02-26 13:05:15 +04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func rightBraceOrBracket(e *Eval) evalStateFn {
|
|
|
|
e.levelStack.pop()
|
|
|
|
|
|
|
|
lowerTyp, ok := e.levelStack.peek()
|
|
|
|
if !ok {
|
|
|
|
return evalRootEnd
|
|
|
|
}
|
2019-10-19 01:17:00 +04:00
|
|
|
|
|
|
|
switch lowerTyp {
|
|
|
|
case jsonBraceLeft:
|
|
|
|
return evalObjectAfterValue
|
|
|
|
case jsonBracketLeft:
|
|
|
|
return evalArrayAfterValue
|
|
|
|
}
|
|
|
|
|
2019-02-26 13:05:15 +04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func evalArrayAfterOpen(e *Eval, i *Item) evalStateFn {
|
|
|
|
e.prevIndex = -1
|
|
|
|
|
|
|
|
switch i.typ {
|
|
|
|
case jsonNull, jsonNumber, jsonString, jsonBool, jsonBraceLeft, jsonBracketLeft:
|
|
|
|
return evalArrayValue(e, i)
|
|
|
|
case jsonBracketRight:
|
|
|
|
setPrevIndex(e)
|
|
|
|
return rightBraceOrBracket(e)
|
|
|
|
case jsonError:
|
|
|
|
return evalError(e, i)
|
|
|
|
default:
|
|
|
|
e.Error = errors.New(UnexpectedToken)
|
|
|
|
}
|
2019-10-19 02:14:19 +04:00
|
|
|
|
2019-02-26 13:05:15 +04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func evalArrayValue(e *Eval, i *Item) evalStateFn {
|
|
|
|
e.prevIndex++
|
|
|
|
e.location.push(e.prevIndex)
|
|
|
|
|
|
|
|
switch i.typ {
|
|
|
|
case jsonNull, jsonNumber, jsonString, jsonBool:
|
|
|
|
return evalArrayAfterValue
|
|
|
|
case jsonBraceLeft:
|
|
|
|
e.levelStack.push(i.typ)
|
|
|
|
return evalObjectAfterOpen
|
|
|
|
case jsonBracketLeft:
|
|
|
|
e.levelStack.push(i.typ)
|
|
|
|
return evalArrayAfterOpen
|
|
|
|
case jsonError:
|
|
|
|
return evalError(e, i)
|
|
|
|
default:
|
|
|
|
e.Error = errors.New(UnexpectedToken)
|
|
|
|
}
|
2019-10-19 02:14:19 +04:00
|
|
|
|
2019-02-26 13:05:15 +04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func evalArrayAfterValue(e *Eval, i *Item) evalStateFn {
|
|
|
|
switch i.typ {
|
|
|
|
case jsonComma:
|
|
|
|
if val, ok := e.location.pop(); ok {
|
|
|
|
if valIndex, ok := val.(int); ok {
|
|
|
|
e.prevIndex = valIndex
|
|
|
|
}
|
|
|
|
}
|
2019-10-19 02:14:19 +04:00
|
|
|
|
2019-02-26 13:05:15 +04:00
|
|
|
return evalArrayValue
|
|
|
|
case jsonBracketRight:
|
|
|
|
e.location.pop()
|
|
|
|
setPrevIndex(e)
|
2019-10-19 02:14:19 +04:00
|
|
|
|
2019-02-26 13:05:15 +04:00
|
|
|
return rightBraceOrBracket(e)
|
|
|
|
case jsonError:
|
|
|
|
return evalError(e, i)
|
|
|
|
default:
|
|
|
|
e.Error = errors.New(UnexpectedToken)
|
|
|
|
}
|
2019-10-19 02:14:19 +04:00
|
|
|
|
2019-02-26 13:05:15 +04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func setPrevIndex(e *Eval) {
|
|
|
|
e.prevIndex = -1
|
2019-10-19 02:14:19 +04:00
|
|
|
|
2019-02-26 13:05:15 +04:00
|
|
|
peeked, ok := e.location.peek()
|
|
|
|
if ok {
|
|
|
|
if peekedIndex, intOk := peeked.(int); intOk {
|
|
|
|
e.prevIndex = peekedIndex
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func evalRootEnd(e *Eval, i *Item) evalStateFn {
|
|
|
|
if i.typ != jsonEOF {
|
|
|
|
if i.typ == jsonError {
|
|
|
|
evalError(e, i)
|
|
|
|
} else {
|
|
|
|
e.Error = errors.New(BadStructure)
|
|
|
|
}
|
|
|
|
}
|
2019-10-19 02:14:19 +04:00
|
|
|
|
2019-02-26 13:05:15 +04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func evalError(e *Eval, i *Item) evalStateFn {
|
|
|
|
e.Error = fmt.Errorf("%s at byte index %d", string(i.val), i.pos)
|
|
|
|
return nil
|
|
|
|
}
|