| | |
| | |
| | |
| |
|
| | |
| |
|
| | package json |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | import ( |
| | "strconv" |
| | "sync" |
| | ) |
| |
|
| | |
| | func Valid(data []byte) bool { |
| | scan := newScanner() |
| | defer freeScanner(scan) |
| | return checkValid(data, scan) == nil |
| | } |
| |
|
| | |
| | |
| | |
| | func checkValid(data []byte, scan *scanner) error { |
| | scan.reset() |
| | for _, c := range data { |
| | scan.bytes++ |
| | if scan.step(scan, c) == scanError { |
| | return scan.err |
| | } |
| | } |
| | if scan.eof() == scanError { |
| | return scan.err |
| | } |
| | return nil |
| | } |
| |
|
| | |
| | |
| | type SyntaxError struct { |
| | msg string |
| | Offset int64 |
| | } |
| |
|
| | func (e *SyntaxError) Error() string { return e.msg } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | type scanner struct { |
| | |
| | |
| | |
| | |
| | step func(*scanner, byte) int |
| |
|
| | |
| | endTop bool |
| |
|
| | |
| | parseState []int |
| |
|
| | |
| | err error |
| |
|
| | |
| | |
| | bytes int64 |
| | } |
| |
|
| | var scannerPool = sync.Pool{ |
| | New: func() any { |
| | return &scanner{} |
| | }, |
| | } |
| |
|
| | func newScanner() *scanner { |
| | scan := scannerPool.Get().(*scanner) |
| | |
| | scan.bytes = 0 |
| | scan.reset() |
| | return scan |
| | } |
| |
|
| | func freeScanner(scan *scanner) { |
| | |
| | if len(scan.parseState) > 1024 { |
| | scan.parseState = nil |
| | } |
| | scannerPool.Put(scan) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | const ( |
| | |
| | scanContinue = iota |
| | scanBeginLiteral |
| | scanBeginObject |
| | scanObjectKey |
| | scanObjectValue |
| | scanEndObject |
| | scanBeginArray |
| | scanArrayValue |
| | scanEndArray |
| | scanSkipSpace |
| |
|
| | |
| | scanEnd |
| | scanError |
| | ) |
| |
|
| | |
| | |
| | |
| | |
| | const ( |
| | parseObjectKey = iota |
| | parseObjectValue |
| | parseArrayValue |
| | ) |
| |
|
| | |
| | |
| | const maxNestingDepth = 10000 |
| |
|
| | |
| | |
| | func (s *scanner) reset() { |
| | s.step = stateBeginValue |
| | s.parseState = s.parseState[0:0] |
| | s.err = nil |
| | s.endTop = false |
| | } |
| |
|
| | |
| | |
| | func (s *scanner) eof() int { |
| | if s.err != nil { |
| | return scanError |
| | } |
| | if s.endTop { |
| | return scanEnd |
| | } |
| | s.step(s, ' ') |
| | if s.endTop { |
| | return scanEnd |
| | } |
| | if s.err == nil { |
| | s.err = &SyntaxError{"unexpected end of JSON input", s.bytes} |
| | } |
| | return scanError |
| | } |
| |
|
| | |
| | |
| | func (s *scanner) pushParseState(c byte, newParseState int, successState int) int { |
| | s.parseState = append(s.parseState, newParseState) |
| | if len(s.parseState) <= maxNestingDepth { |
| | return successState |
| | } |
| | return s.error(c, "exceeded max depth") |
| | } |
| |
|
| | |
| | |
| | func (s *scanner) popParseState() { |
| | n := len(s.parseState) - 1 |
| | s.parseState = s.parseState[0:n] |
| | if n == 0 { |
| | s.step = stateEndTop |
| | s.endTop = true |
| | } else { |
| | s.step = stateEndValue |
| | } |
| | } |
| |
|
| | func isSpace(c byte) bool { |
| | return c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') |
| | } |
| |
|
| | |
| | func stateBeginValueOrEmpty(s *scanner, c byte) int { |
| | if isSpace(c) { |
| | return scanSkipSpace |
| | } |
| | if c == ']' { |
| | return stateEndValue(s, c) |
| | } |
| | return stateBeginValue(s, c) |
| | } |
| |
|
| | |
| | func stateBeginValue(s *scanner, c byte) int { |
| | if isSpace(c) { |
| | return scanSkipSpace |
| | } |
| | switch c { |
| | case '{': |
| | s.step = stateBeginStringOrEmpty |
| | return s.pushParseState(c, parseObjectKey, scanBeginObject) |
| | case '[': |
| | s.step = stateBeginValueOrEmpty |
| | return s.pushParseState(c, parseArrayValue, scanBeginArray) |
| | case '"': |
| | s.step = stateInString |
| | return scanBeginLiteral |
| | case '-': |
| | s.step = stateNeg |
| | return scanBeginLiteral |
| | case '0': |
| | s.step = state0 |
| | return scanBeginLiteral |
| | case 't': |
| | s.step = stateT |
| | return scanBeginLiteral |
| | case 'f': |
| | s.step = stateF |
| | return scanBeginLiteral |
| | case 'n': |
| | s.step = stateN |
| | return scanBeginLiteral |
| | } |
| | if '1' <= c && c <= '9' { |
| | s.step = state1 |
| | return scanBeginLiteral |
| | } |
| | return s.error(c, "looking for beginning of value") |
| | } |
| |
|
| | |
| | func stateBeginStringOrEmpty(s *scanner, c byte) int { |
| | if isSpace(c) { |
| | return scanSkipSpace |
| | } |
| | if c == '}' { |
| | n := len(s.parseState) |
| | s.parseState[n-1] = parseObjectValue |
| | return stateEndValue(s, c) |
| | } |
| | return stateBeginString(s, c) |
| | } |
| |
|
| | |
| | func stateBeginString(s *scanner, c byte) int { |
| | if isSpace(c) { |
| | return scanSkipSpace |
| | } |
| | if c == '"' { |
| | s.step = stateInString |
| | return scanBeginLiteral |
| | } |
| | return s.error(c, "looking for beginning of object key string") |
| | } |
| |
|
| | |
| | |
| | func stateEndValue(s *scanner, c byte) int { |
| | n := len(s.parseState) |
| | if n == 0 { |
| | |
| | s.step = stateEndTop |
| | s.endTop = true |
| | return stateEndTop(s, c) |
| | } |
| | if isSpace(c) { |
| | s.step = stateEndValue |
| | return scanSkipSpace |
| | } |
| | ps := s.parseState[n-1] |
| | switch ps { |
| | case parseObjectKey: |
| | if c == ':' { |
| | s.parseState[n-1] = parseObjectValue |
| | s.step = stateBeginValue |
| | return scanObjectKey |
| | } |
| | return s.error(c, "after object key") |
| | case parseObjectValue: |
| | if c == ',' { |
| | s.parseState[n-1] = parseObjectKey |
| | s.step = stateBeginString |
| | return scanObjectValue |
| | } |
| | if c == '}' { |
| | s.popParseState() |
| | return scanEndObject |
| | } |
| | return s.error(c, "after object key:value pair") |
| | case parseArrayValue: |
| | if c == ',' { |
| | s.step = stateBeginValue |
| | return scanArrayValue |
| | } |
| | if c == ']' { |
| | s.popParseState() |
| | return scanEndArray |
| | } |
| | return s.error(c, "after array element") |
| | } |
| | return s.error(c, "") |
| | } |
| |
|
| | |
| | |
| | |
| | func stateEndTop(s *scanner, c byte) int { |
| | if !isSpace(c) { |
| | |
| | s.error(c, "after top-level value") |
| | } |
| | return scanEnd |
| | } |
| |
|
| | |
| | func stateInString(s *scanner, c byte) int { |
| | if c == '"' { |
| | s.step = stateEndValue |
| | return scanContinue |
| | } |
| | if c == '\\' { |
| | s.step = stateInStringEsc |
| | return scanContinue |
| | } |
| | if c < 0x20 { |
| | return s.error(c, "in string literal") |
| | } |
| | return scanContinue |
| | } |
| |
|
| | |
| | func stateInStringEsc(s *scanner, c byte) int { |
| | switch c { |
| | case 'b', 'f', 'n', 'r', 't', '\\', '/', '"': |
| | s.step = stateInString |
| | return scanContinue |
| | case 'u': |
| | s.step = stateInStringEscU |
| | return scanContinue |
| | } |
| | return s.error(c, "in string escape code") |
| | } |
| |
|
| | |
| | func stateInStringEscU(s *scanner, c byte) int { |
| | if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { |
| | s.step = stateInStringEscU1 |
| | return scanContinue |
| | } |
| | |
| | return s.error(c, "in \\u hexadecimal character escape") |
| | } |
| |
|
| | |
| | func stateInStringEscU1(s *scanner, c byte) int { |
| | if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { |
| | s.step = stateInStringEscU12 |
| | return scanContinue |
| | } |
| | |
| | return s.error(c, "in \\u hexadecimal character escape") |
| | } |
| |
|
| | |
| | func stateInStringEscU12(s *scanner, c byte) int { |
| | if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { |
| | s.step = stateInStringEscU123 |
| | return scanContinue |
| | } |
| | |
| | return s.error(c, "in \\u hexadecimal character escape") |
| | } |
| |
|
| | |
| | func stateInStringEscU123(s *scanner, c byte) int { |
| | if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { |
| | s.step = stateInString |
| | return scanContinue |
| | } |
| | |
| | return s.error(c, "in \\u hexadecimal character escape") |
| | } |
| |
|
| | |
| | func stateNeg(s *scanner, c byte) int { |
| | if c == '0' { |
| | s.step = state0 |
| | return scanContinue |
| | } |
| | if '1' <= c && c <= '9' { |
| | s.step = state1 |
| | return scanContinue |
| | } |
| | return s.error(c, "in numeric literal") |
| | } |
| |
|
| | |
| | |
| | func state1(s *scanner, c byte) int { |
| | if '0' <= c && c <= '9' { |
| | s.step = state1 |
| | return scanContinue |
| | } |
| | return state0(s, c) |
| | } |
| |
|
| | |
| | func state0(s *scanner, c byte) int { |
| | if c == '.' { |
| | s.step = stateDot |
| | return scanContinue |
| | } |
| | if c == 'e' || c == 'E' { |
| | s.step = stateE |
| | return scanContinue |
| | } |
| | return stateEndValue(s, c) |
| | } |
| |
|
| | |
| | |
| | func stateDot(s *scanner, c byte) int { |
| | if '0' <= c && c <= '9' { |
| | s.step = stateDot0 |
| | return scanContinue |
| | } |
| | return s.error(c, "after decimal point in numeric literal") |
| | } |
| |
|
| | |
| | |
| | func stateDot0(s *scanner, c byte) int { |
| | if '0' <= c && c <= '9' { |
| | return scanContinue |
| | } |
| | if c == 'e' || c == 'E' { |
| | s.step = stateE |
| | return scanContinue |
| | } |
| | return stateEndValue(s, c) |
| | } |
| |
|
| | |
| | |
| | func stateE(s *scanner, c byte) int { |
| | if c == '+' || c == '-' { |
| | s.step = stateESign |
| | return scanContinue |
| | } |
| | return stateESign(s, c) |
| | } |
| |
|
| | |
| | |
| | func stateESign(s *scanner, c byte) int { |
| | if '0' <= c && c <= '9' { |
| | s.step = stateE0 |
| | return scanContinue |
| | } |
| | return s.error(c, "in exponent of numeric literal") |
| | } |
| |
|
| | |
| | |
| | |
| | func stateE0(s *scanner, c byte) int { |
| | if '0' <= c && c <= '9' { |
| | return scanContinue |
| | } |
| | return stateEndValue(s, c) |
| | } |
| |
|
| | |
| | func stateT(s *scanner, c byte) int { |
| | if c == 'r' { |
| | s.step = stateTr |
| | return scanContinue |
| | } |
| | return s.error(c, "in literal true (expecting 'r')") |
| | } |
| |
|
| | |
| | func stateTr(s *scanner, c byte) int { |
| | if c == 'u' { |
| | s.step = stateTru |
| | return scanContinue |
| | } |
| | return s.error(c, "in literal true (expecting 'u')") |
| | } |
| |
|
| | |
| | func stateTru(s *scanner, c byte) int { |
| | if c == 'e' { |
| | s.step = stateEndValue |
| | return scanContinue |
| | } |
| | return s.error(c, "in literal true (expecting 'e')") |
| | } |
| |
|
| | |
| | func stateF(s *scanner, c byte) int { |
| | if c == 'a' { |
| | s.step = stateFa |
| | return scanContinue |
| | } |
| | return s.error(c, "in literal false (expecting 'a')") |
| | } |
| |
|
| | |
| | func stateFa(s *scanner, c byte) int { |
| | if c == 'l' { |
| | s.step = stateFal |
| | return scanContinue |
| | } |
| | return s.error(c, "in literal false (expecting 'l')") |
| | } |
| |
|
| | |
| | func stateFal(s *scanner, c byte) int { |
| | if c == 's' { |
| | s.step = stateFals |
| | return scanContinue |
| | } |
| | return s.error(c, "in literal false (expecting 's')") |
| | } |
| |
|
| | |
| | func stateFals(s *scanner, c byte) int { |
| | if c == 'e' { |
| | s.step = stateEndValue |
| | return scanContinue |
| | } |
| | return s.error(c, "in literal false (expecting 'e')") |
| | } |
| |
|
| | |
| | func stateN(s *scanner, c byte) int { |
| | if c == 'u' { |
| | s.step = stateNu |
| | return scanContinue |
| | } |
| | return s.error(c, "in literal null (expecting 'u')") |
| | } |
| |
|
| | |
| | func stateNu(s *scanner, c byte) int { |
| | if c == 'l' { |
| | s.step = stateNul |
| | return scanContinue |
| | } |
| | return s.error(c, "in literal null (expecting 'l')") |
| | } |
| |
|
| | |
| | func stateNul(s *scanner, c byte) int { |
| | if c == 'l' { |
| | s.step = stateEndValue |
| | return scanContinue |
| | } |
| | return s.error(c, "in literal null (expecting 'l')") |
| | } |
| |
|
| | |
| | |
| | func stateError(s *scanner, c byte) int { |
| | return scanError |
| | } |
| |
|
| | |
| | func (s *scanner) error(c byte, context string) int { |
| | s.step = stateError |
| | s.err = &SyntaxError{"invalid character " + quoteChar(c) + " " + context, s.bytes} |
| | return scanError |
| | } |
| |
|
| | |
| | func quoteChar(c byte) string { |
| | |
| | if c == '\'' { |
| | return `'\''` |
| | } |
| | if c == '"' { |
| | return `'"'` |
| | } |
| |
|
| | |
| | s := strconv.Quote(string(c)) |
| | return "'" + s[1:len(s)-1] + "'" |
| | } |
| |
|