298 lines
5.4 KiB
Go
298 lines
5.4 KiB
Go
package jsonpath
|
|
|
|
const (
|
|
jsonError = iota
|
|
jsonEOF
|
|
|
|
jsonBraceLeft
|
|
jsonBraceRight
|
|
jsonBracketLeft
|
|
jsonBracketRight
|
|
jsonColon
|
|
jsonComma
|
|
jsonNumber
|
|
jsonString
|
|
jsonNull
|
|
jsonKey
|
|
jsonBool
|
|
)
|
|
|
|
var trueBytes = []byte{'t', 'r', 'u', 'e'}
|
|
var falseBytes = []byte{'f', 'a', 'l', 's', 'e'}
|
|
var nullBytes = []byte{'n', 'u', 'l', 'l'}
|
|
|
|
var jsonTokenNames = map[int]string{
|
|
jsonEOF: "EOF",
|
|
jsonError: "ERROR",
|
|
|
|
jsonBraceLeft: "{",
|
|
jsonBraceRight: "}",
|
|
jsonBracketLeft: "[",
|
|
jsonBracketRight: "]",
|
|
jsonColon: ":",
|
|
jsonComma: ",",
|
|
jsonNumber: "NUMBER",
|
|
jsonString: "STRING",
|
|
jsonNull: "NULL",
|
|
jsonKey: "KEY",
|
|
jsonBool: "BOOL",
|
|
}
|
|
|
|
var JSON = lexJSONRoot
|
|
|
|
func lexJSONRoot(l lexer, state *intStack) stateFn {
|
|
var next stateFn
|
|
|
|
ignoreSpaceRun(l)
|
|
|
|
cur := l.peek()
|
|
switch cur {
|
|
case '{':
|
|
next = stateJSONObjectOpen
|
|
case '[':
|
|
next = stateJSONArrayOpen
|
|
default:
|
|
next = l.errorf("Expected '{' or '[' at root of JSON instead of %#U", cur)
|
|
}
|
|
|
|
return next
|
|
}
|
|
|
|
func stateJSONObjectOpen(l lexer, state *intStack) stateFn {
|
|
cur := l.take()
|
|
if cur != '{' {
|
|
return l.errorf("Expected '{' as start of object instead of %#U", cur)
|
|
}
|
|
|
|
l.emit(jsonBraceLeft)
|
|
state.push(jsonBraceLeft)
|
|
|
|
return stateJSONObject
|
|
}
|
|
|
|
func stateJSONArrayOpen(l lexer, state *intStack) stateFn {
|
|
cur := l.take()
|
|
if cur != '[' {
|
|
return l.errorf("Expected '[' as start of array instead of %#U", cur)
|
|
}
|
|
|
|
l.emit(jsonBracketLeft)
|
|
state.push(jsonBracketLeft)
|
|
|
|
return stateJSONArray
|
|
}
|
|
|
|
func stateJSONObject(l lexer, state *intStack) stateFn {
|
|
var next stateFn
|
|
|
|
cur := l.peek()
|
|
switch cur {
|
|
case '}':
|
|
if top, ok := state.peek(); ok && top != jsonBraceLeft {
|
|
next = l.errorf("Received %#U but has no matching '{'", cur)
|
|
break
|
|
}
|
|
|
|
l.take()
|
|
l.emit(jsonBraceRight)
|
|
state.pop()
|
|
|
|
next = stateJSONAfterValue
|
|
case '"':
|
|
next = stateJSONKey
|
|
default:
|
|
next = l.errorf("Expected '}' or \" within an object instead of %#U", cur)
|
|
}
|
|
|
|
return next
|
|
}
|
|
|
|
func stateJSONArray(l lexer, state *intStack) stateFn {
|
|
var next stateFn
|
|
|
|
cur := l.peek()
|
|
switch cur {
|
|
case ']':
|
|
if top, ok := state.peek(); ok && top != jsonBracketLeft {
|
|
next = l.errorf("Received %#U but has no matching '['", cur)
|
|
break
|
|
}
|
|
|
|
l.take()
|
|
l.emit(jsonBracketRight)
|
|
state.pop()
|
|
|
|
next = stateJSONAfterValue
|
|
default:
|
|
next = stateJSONValue
|
|
}
|
|
|
|
return next
|
|
}
|
|
|
|
func stateJSONAfterValue(l lexer, state *intStack) stateFn {
|
|
cur := l.take()
|
|
topVal := noValue
|
|
|
|
top, ok := state.peek()
|
|
if ok {
|
|
topVal = top
|
|
}
|
|
|
|
switch cur {
|
|
case ',':
|
|
l.emit(jsonComma)
|
|
|
|
switch topVal {
|
|
case jsonBraceLeft:
|
|
return stateJSONKey
|
|
case jsonBracketLeft:
|
|
return stateJSONValue
|
|
case noValue:
|
|
return l.errorf("found %#U outside of array or object", cur)
|
|
default:
|
|
return l.errorf("unexpected character in lexer stack: %#U", cur)
|
|
}
|
|
case '}':
|
|
l.emit(jsonBraceRight)
|
|
state.pop()
|
|
|
|
switch topVal {
|
|
case jsonBraceLeft:
|
|
return stateJSONAfterValue
|
|
case jsonBracketLeft:
|
|
return l.errorf("unexpected %#U in array", cur)
|
|
case noValue:
|
|
return stateJSONAfterRoot
|
|
}
|
|
case ']':
|
|
l.emit(jsonBracketRight)
|
|
state.pop()
|
|
|
|
switch topVal {
|
|
case jsonBraceLeft:
|
|
return l.errorf("unexpected %#U in object", cur)
|
|
case jsonBracketLeft:
|
|
return stateJSONAfterValue
|
|
case noValue:
|
|
return stateJSONAfterRoot
|
|
}
|
|
case eof:
|
|
if state.len() == 0 {
|
|
l.emit(jsonEOF)
|
|
return nil
|
|
}
|
|
|
|
return l.errorf("unexpected EOF instead of value")
|
|
default:
|
|
return l.errorf("unexpected character after json value token: %#U", cur)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func stateJSONKey(l lexer, state *intStack) stateFn {
|
|
if err := l.takeString(); err != nil {
|
|
return l.errorf(err.Error())
|
|
}
|
|
|
|
l.emit(jsonKey)
|
|
|
|
return stateJSONColon
|
|
}
|
|
|
|
func stateJSONColon(l lexer, state *intStack) stateFn {
|
|
cur := l.take()
|
|
if cur != ':' {
|
|
return l.errorf("expected ':' after key string instead of %#U", cur)
|
|
}
|
|
|
|
l.emit(jsonColon)
|
|
|
|
return stateJSONValue
|
|
}
|
|
|
|
func stateJSONValue(l lexer, state *intStack) stateFn {
|
|
cur := l.peek()
|
|
|
|
switch cur {
|
|
case eof:
|
|
return l.errorf("Unexpected EOF instead of value")
|
|
case '"':
|
|
return stateJSONString
|
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
|
return stateJSONNumber
|
|
case 't', 'f':
|
|
return stateJSONBool
|
|
case 'n':
|
|
return stateJSONNull
|
|
case '{':
|
|
return stateJSONObjectOpen
|
|
case '[':
|
|
return stateJSONArrayOpen
|
|
default:
|
|
return l.errorf("unexpected character as start of value: %#U", cur)
|
|
}
|
|
}
|
|
|
|
func stateJSONString(l lexer, state *intStack) stateFn {
|
|
if err := l.takeString(); err != nil {
|
|
return l.errorf(err.Error())
|
|
}
|
|
|
|
l.emit(jsonString)
|
|
|
|
return stateJSONAfterValue
|
|
}
|
|
|
|
func stateJSONNumber(l lexer, state *intStack) stateFn {
|
|
if err := takeJSONNumeric(l); err != nil {
|
|
return l.errorf(err.Error())
|
|
}
|
|
|
|
l.emit(jsonNumber)
|
|
|
|
return stateJSONAfterValue
|
|
}
|
|
|
|
func stateJSONBool(l lexer, state *intStack) stateFn {
|
|
var match []byte
|
|
|
|
cur := l.peek()
|
|
switch cur {
|
|
case 't':
|
|
match = trueBytes
|
|
case 'f':
|
|
match = falseBytes
|
|
}
|
|
|
|
if !takeExactSequence(l, match) {
|
|
return l.errorf("Could not parse value as 'true' or 'false'")
|
|
}
|
|
|
|
l.emit(jsonBool)
|
|
|
|
return stateJSONAfterValue
|
|
}
|
|
|
|
func stateJSONNull(l lexer, state *intStack) stateFn {
|
|
if !takeExactSequence(l, nullBytes) {
|
|
return l.errorf("Could not parse value as 'null'")
|
|
}
|
|
|
|
l.emit(jsonNull)
|
|
|
|
return stateJSONAfterValue
|
|
}
|
|
|
|
func stateJSONAfterRoot(l lexer, state *intStack) stateFn {
|
|
cur := l.take()
|
|
if cur != eof {
|
|
return l.errorf("Expected EOF instead of %#U", cur)
|
|
}
|
|
|
|
l.emit(jsonEOF)
|
|
|
|
return nil
|
|
}
|