diff options
Diffstat (limited to 'vendor/github.com/d5/tengo/stdlib/json/decode.go')
-rw-r--r-- | vendor/github.com/d5/tengo/stdlib/json/decode.go | 374 |
1 files changed, 0 insertions, 374 deletions
diff --git a/vendor/github.com/d5/tengo/stdlib/json/decode.go b/vendor/github.com/d5/tengo/stdlib/json/decode.go deleted file mode 100644 index 5a3fe6c7..00000000 --- a/vendor/github.com/d5/tengo/stdlib/json/decode.go +++ /dev/null @@ -1,374 +0,0 @@ -// A modified version of Go's JSON implementation. - -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package json - -import ( - "strconv" - "unicode" - "unicode/utf16" - "unicode/utf8" - - "github.com/d5/tengo/objects" -) - -// Decode parses the JSON-encoded data and returns the result object. -func Decode(data []byte) (objects.Object, error) { - var d decodeState - err := checkValid(data, &d.scan) - if err != nil { - return nil, err - } - - d.init(data) - d.scan.reset() - d.scanWhile(scanSkipSpace) - - return d.value() -} - -// decodeState represents the state while decoding a JSON value. -type decodeState struct { - data []byte - off int // next read offset in data - opcode int // last read result - scan scanner -} - -// readIndex returns the position of the last byte read. -func (d *decodeState) readIndex() int { - return d.off - 1 -} - -const phasePanicMsg = "JSON decoder out of sync - data changing underfoot?" - -func (d *decodeState) init(data []byte) *decodeState { - d.data = data - d.off = 0 - return d -} - -// scanNext processes the byte at d.data[d.off]. -func (d *decodeState) scanNext() { - if d.off < len(d.data) { - d.opcode = d.scan.step(&d.scan, d.data[d.off]) - d.off++ - } else { - d.opcode = d.scan.eof() - d.off = len(d.data) + 1 // mark processed EOF with len+1 - } -} - -// scanWhile processes bytes in d.data[d.off:] until it -// receives a scan code not equal to op. -func (d *decodeState) scanWhile(op int) { - s, data, i := &d.scan, d.data, d.off - for i < len(data) { - newOp := s.step(s, data[i]) - i++ - if newOp != op { - d.opcode = newOp - d.off = i - return - } - } - - d.off = len(data) + 1 // mark processed EOF with len+1 - d.opcode = d.scan.eof() -} - -func (d *decodeState) value() (objects.Object, error) { - switch d.opcode { - default: - panic(phasePanicMsg) - - case scanBeginArray: - o, err := d.array() - if err != nil { - return nil, err - } - - d.scanNext() - - return o, nil - - case scanBeginObject: - o, err := d.object() - if err != nil { - return nil, err - } - - d.scanNext() - - return o, nil - - case scanBeginLiteral: - return d.literal() - } -} - -func (d *decodeState) array() (objects.Object, error) { - var arr []objects.Object - for { - // Look ahead for ] - can only happen on first iteration. - d.scanWhile(scanSkipSpace) - if d.opcode == scanEndArray { - break - } - - o, err := d.value() - if err != nil { - return nil, err - } - arr = append(arr, o) - - // Next token must be , or ]. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode == scanEndArray { - break - } - if d.opcode != scanArrayValue { - panic(phasePanicMsg) - } - } - - return &objects.Array{Value: arr}, nil -} - -func (d *decodeState) object() (objects.Object, error) { - m := make(map[string]objects.Object) - for { - // Read opening " of string key or closing }. - d.scanWhile(scanSkipSpace) - if d.opcode == scanEndObject { - // closing } - can only happen on first iteration. - break - } - if d.opcode != scanBeginLiteral { - panic(phasePanicMsg) - } - - // Read string key. - start := d.readIndex() - d.scanWhile(scanContinue) - item := d.data[start:d.readIndex()] - key, ok := unquote(item) - if !ok { - panic(phasePanicMsg) - } - - // Read : before value. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode != scanObjectKey { - panic(phasePanicMsg) - } - d.scanWhile(scanSkipSpace) - - // Read value. - o, err := d.value() - if err != nil { - return nil, err - } - - m[key] = o - - // Next token must be , or }. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode == scanEndObject { - break - } - if d.opcode != scanObjectValue { - panic(phasePanicMsg) - } - } - - return &objects.Map{Value: m}, nil -} - -func (d *decodeState) literal() (objects.Object, error) { - // All bytes inside literal return scanContinue op code. - start := d.readIndex() - d.scanWhile(scanContinue) - - item := d.data[start:d.readIndex()] - - switch c := item[0]; c { - case 'n': // null - return objects.UndefinedValue, nil - - case 't', 'f': // true, false - if c == 't' { - return objects.TrueValue, nil - } - return objects.FalseValue, nil - - case '"': // string - s, ok := unquote(item) - if !ok { - panic(phasePanicMsg) - } - return &objects.String{Value: s}, nil - - default: // number - if c != '-' && (c < '0' || c > '9') { - panic(phasePanicMsg) - } - - n, _ := strconv.ParseFloat(string(item), 10) - return &objects.Float{Value: n}, nil - } -} - -// getu4 decodes \uXXXX from the beginning of s, returning the hex value, -// or it returns -1. -func getu4(s []byte) rune { - if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { - return -1 - } - var r rune - for _, c := range s[2:6] { - switch { - case '0' <= c && c <= '9': - c = c - '0' - case 'a' <= c && c <= 'f': - c = c - 'a' + 10 - case 'A' <= c && c <= 'F': - c = c - 'A' + 10 - default: - return -1 - } - r = r*16 + rune(c) - } - return r -} - -// unquote converts a quoted JSON string literal s into an actual string t. -// The rules are different than for Go, so cannot use strconv.Unquote. -func unquote(s []byte) (t string, ok bool) { - s, ok = unquoteBytes(s) - t = string(s) - return -} - -func unquoteBytes(s []byte) (t []byte, ok bool) { - if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { - return - } - s = s[1 : len(s)-1] - - // Check for unusual characters. If there are none, - // then no unquoting is needed, so return a slice of the - // original bytes. - r := 0 - for r < len(s) { - c := s[r] - if c == '\\' || c == '"' || c < ' ' { - break - } - if c < utf8.RuneSelf { - r++ - continue - } - rr, size := utf8.DecodeRune(s[r:]) - if rr == utf8.RuneError && size == 1 { - break - } - r += size - } - if r == len(s) { - return s, true - } - - b := make([]byte, len(s)+2*utf8.UTFMax) - w := copy(b, s[0:r]) - for r < len(s) { - // Out of room? Can only happen if s is full of - // malformed UTF-8 and we're replacing each - // byte with RuneError. - if w >= len(b)-2*utf8.UTFMax { - nb := make([]byte, (len(b)+utf8.UTFMax)*2) - copy(nb, b[0:w]) - b = nb - } - switch c := s[r]; { - case c == '\\': - r++ - if r >= len(s) { - return - } - switch s[r] { - default: - return - case '"', '\\', '/', '\'': - b[w] = s[r] - r++ - w++ - case 'b': - b[w] = '\b' - r++ - w++ - case 'f': - b[w] = '\f' - r++ - w++ - case 'n': - b[w] = '\n' - r++ - w++ - case 'r': - b[w] = '\r' - r++ - w++ - case 't': - b[w] = '\t' - r++ - w++ - case 'u': - r-- - rr := getu4(s[r:]) - if rr < 0 { - return - } - r += 6 - if utf16.IsSurrogate(rr) { - rr1 := getu4(s[r:]) - if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { - // A valid pair; consume. - r += 6 - w += utf8.EncodeRune(b[w:], dec) - break - } - // Invalid surrogate; fall back to replacement rune. - rr = unicode.ReplacementChar - } - w += utf8.EncodeRune(b[w:], rr) - } - - // Quote, control characters are invalid. - case c == '"', c < ' ': - return - - // ASCII - case c < utf8.RuneSelf: - b[w] = c - r++ - w++ - - // Coerce to well-formed UTF-8. - default: - rr, size := utf8.DecodeRune(s[r:]) - r += size - w += utf8.EncodeRune(b[w:], rr) - } - } - return b[0:w], true -} |