jsonpath/path_states.go

227 lines
3.8 KiB
Go

package jsonpath
const (
pathError = iota
pathEOF
pathRoot
pathCurrent
pathKey
pathBracketLeft
pathBracketRight
pathIndex
pathOr
pathIndexRange
pathLength
pathWildcard
pathPeriod
pathValue
pathWhere
pathExpression
)
var pathTokenNames = map[int]string{
pathError: "ERROR",
pathEOF: "EOF",
pathRoot: "$",
pathCurrent: "@",
pathKey: "KEY",
pathBracketLeft: "[",
pathBracketRight: "]",
pathIndex: "INDEX",
pathOr: "|",
pathIndexRange: ":",
pathLength: "LENGTH",
pathWildcard: "*",
pathPeriod: ".",
pathValue: "+",
pathWhere: "?",
pathExpression: "EXPRESSION",
}
var PATH = lexPathStart
func lexPathStart(l lexer, state *intStack) stateFn {
ignoreSpaceRun(l)
cur := l.take()
switch cur {
case '$':
l.emit(pathRoot)
case '@':
l.emit(pathCurrent)
default:
return l.errorf("Expected $ or @ at start of path instead of %#U", cur)
}
return lexPathAfterKey
}
func lexPathAfterKey(l lexer, state *intStack) stateFn {
cur := l.take()
switch cur {
case '.':
l.emit(pathPeriod)
return lexKey
case '[':
l.emit(pathBracketLeft)
return lexPathBracketOpen
case '+':
l.emit(pathValue)
return lexPathAfterValue
case '?':
l.emit(pathWhere)
return lexPathExpression
case eof:
l.emit(pathEOF)
default:
return l.errorf("Unrecognized rune after path element %#U", cur)
}
return nil
}
func lexPathExpression(l lexer, state *intStack) stateFn {
cur := l.take()
if cur != '(' {
return l.errorf("Expected $ at start of path instead of %#U", cur)
}
parenLeftCount := 1
for {
cur = l.take()
switch cur {
case '(':
parenLeftCount++
case ')':
parenLeftCount--
case eof:
return l.errorf("Unexpected EOF within expression")
}
if parenLeftCount == 0 {
break
}
}
l.emit(pathExpression)
return lexPathAfterKey
}
func lexPathBracketOpen(l lexer, state *intStack) stateFn {
switch l.peek() {
case '*':
l.take()
l.emit(pathWildcard)
return lexPathBracketClose
case '"':
// nolint:errcheck
l.takeString()
l.emit(pathKey)
return lexPathBracketClose
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
l.take()
takeDigits(l)
l.emit(pathIndex)
return lexPathIndexRange
case eof:
l.emit(pathEOF)
}
return nil
}
func lexPathBracketClose(l lexer, state *intStack) stateFn {
cur := l.take()
if cur != ']' {
return l.errorf("Expected ] instead of %#U", cur)
}
l.emit(pathBracketRight)
return lexPathAfterKey
}
func lexKey(l lexer, state *intStack) stateFn {
// TODO: Support globbing of keys
switch l.peek() {
case '*':
l.take()
l.emit(pathWildcard)
return lexPathAfterKey
case '"':
// nolint:errcheck
l.takeString()
l.emit(pathKey)
return lexPathAfterKey
case eof:
l.take()
l.emit(pathEOF)
return nil
default:
for {
v := l.peek()
if v == '.' || v == '[' || v == '+' || v == '?' || v == eof {
break
}
l.take()
}
l.emit(pathKey)
return lexPathAfterKey
}
}
func lexPathIndexRange(l lexer, state *intStack) stateFn {
// TODO: Expand supported operations
// Currently only supports single index or wildcard (1 or all)
cur := l.peek()
switch cur {
case ':':
l.take()
l.emit(pathIndexRange)
return lexPathIndexRangeSecond
case ']':
return lexPathBracketClose
default:
return l.errorf("Expected digit or ] instead of %#U", cur)
}
}
func lexPathIndexRangeSecond(l lexer, state *intStack) stateFn {
cur := l.peek()
switch cur {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
takeDigits(l)
l.emit(pathIndex)
return lexPathBracketClose
case ']':
return lexPathBracketClose
default:
return l.errorf("Expected digit or ] instead of %#U", cur)
}
}
func lexPathAfterValue(l lexer, state *intStack) stateFn {
cur := l.take()
if cur != eof {
return l.errorf("Expected EOF instead of %#U", cur)
}
l.emit(pathEOF)
return nil
}