ipld-eth-server/vendor/github.com/polydawn/refmt/json/jsonDecoder.go

208 lines
5.4 KiB
Go
Raw Normal View History

package json
import (
"fmt"
"io"
"github.com/polydawn/refmt/shared"
. "github.com/polydawn/refmt/tok"
)
type Decoder struct {
r shared.SlickReader
stack []decoderStep // When empty, and step returns done, all done.
step decoderStep // Shortcut to end of stack.
some bool // Set to true after first value in any context; use to decide if a comma must precede the next value.
}
func NewDecoder(r io.Reader) (d *Decoder) {
d = &Decoder{
r: shared.NewReader(r),
stack: make([]decoderStep, 0, 10),
}
d.step = d.step_acceptValue
return
}
func (d *Decoder) Reset() {
d.stack = d.stack[0:0]
d.step = d.step_acceptValue
d.some = false
}
type decoderStep func(tokenSlot *Token) (done bool, err error)
func (d *Decoder) Step(tokenSlot *Token) (done bool, err error) {
done, err = d.step(tokenSlot)
// If the step errored: out, entirely.
if err != nil {
return true, err
}
// If the step wasn't done, return same status.
if !done {
return false, nil
}
// If it WAS done, and stack empty, we're entirely done.
nSteps := len(d.stack) - 1
if nSteps <= 0 {
return true, nil // that's all folks
}
// Pop the stack. Reset "some" to true.
d.step = d.stack[nSteps]
d.stack = d.stack[0:nSteps]
d.some = true
return false, nil
}
func (d *Decoder) pushPhase(newPhase decoderStep) {
d.stack = append(d.stack, d.step)
d.step = newPhase
d.some = false
}
func readn1skippingWhitespace(r shared.SlickReader) (majorByte byte, err error) {
for {
majorByte, err = r.Readn1()
switch majorByte {
case ' ', '\t', '\r', '\n': // continue
default:
return
}
}
}
// The original step, where any value is accepted, and no terminators for composites are valid.
// ONLY used in the original step; all other steps handle leaf nodes internally.
func (d *Decoder) step_acceptValue(tokenSlot *Token) (done bool, err error) {
majorByte, err := readn1skippingWhitespace(d.r)
if err != nil {
return true, err
}
return d.stepHelper_acceptValue(majorByte, tokenSlot)
}
// Step in midst of decoding an array.
func (d *Decoder) step_acceptArrValueOrBreak(tokenSlot *Token) (done bool, err error) {
majorByte, err := readn1skippingWhitespace(d.r)
if err != nil {
return true, err
}
if d.some {
switch majorByte {
case ']':
tokenSlot.Type = TArrClose
return true, nil
case ',':
majorByte, err = readn1skippingWhitespace(d.r)
if err != nil {
return true, err
}
// and now fall through to the next switch
}
}
switch majorByte {
case ']':
tokenSlot.Type = TArrClose
return true, nil
default:
_, err := d.stepHelper_acceptValue(majorByte, tokenSlot)
d.some = true
return false, err
}
}
// Step in midst of decoding a map, key expected up next, or end.
func (d *Decoder) step_acceptMapKeyOrBreak(tokenSlot *Token) (done bool, err error) {
majorByte, err := readn1skippingWhitespace(d.r)
if err != nil {
return true, err
}
if d.some {
switch majorByte {
case '}':
tokenSlot.Type = TMapClose
return true, nil
case ',':
majorByte, err = readn1skippingWhitespace(d.r)
if err != nil {
return true, err
}
// and now fall through to the next switch
}
}
switch majorByte {
case '}':
tokenSlot.Type = TMapClose
return true, nil
default:
// Consume a string for key.
_, err := d.stepHelper_acceptValue(majorByte, tokenSlot) // FIXME surely not *any* value? not composites, at least?
// Now scan up to consume the colon as well, which is required next.
majorByte, err = readn1skippingWhitespace(d.r)
if err != nil {
return true, err
}
if majorByte != ':' {
return true, fmt.Errorf("expected colon after map key; got 0x%x", majorByte)
}
// Next up: expect a value.
d.step = d.step_acceptMapValue
d.some = true
return false, err
}
}
// Step in midst of decoding a map, value expected up next.
func (d *Decoder) step_acceptMapValue(tokenSlot *Token) (done bool, err error) {
majorByte, err := readn1skippingWhitespace(d.r)
if err != nil {
return true, err
}
d.step = d.step_acceptMapKeyOrBreak
_, err = d.stepHelper_acceptValue(majorByte, tokenSlot)
return false, err
}
func (d *Decoder) stepHelper_acceptValue(majorByte byte, tokenSlot *Token) (done bool, err error) {
switch majorByte {
case '{':
tokenSlot.Type = TMapOpen
tokenSlot.Length = -1
d.pushPhase(d.step_acceptMapKeyOrBreak)
return false, nil
case '[':
tokenSlot.Type = TArrOpen
tokenSlot.Length = -1
d.pushPhase(d.step_acceptArrValueOrBreak)
return false, nil
case 'n':
d.r.Readnzc(3) // FIXME must check these equal "ull"!
tokenSlot.Type = TNull
return true, nil
case '"':
tokenSlot.Type = TString
tokenSlot.Str, err = d.decodeString()
return true, err
case 'f':
d.r.Readnzc(4) // FIXME must check these equal "alse"!
tokenSlot.Type = TBool
tokenSlot.Bool = false
return true, nil
case 't':
d.r.Readnzc(3) // FIXME must check these equal "rue"!
tokenSlot.Type = TBool
tokenSlot.Bool = true
return true, nil
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
// Some kind of numeric... but in json, we *can't tell* if it's float or int.
// JSON in general doesn't differentiate. But we usually try to anyway.
// (If this results in us yielding an int, and an obj.Unmarshaller is filling a float,
// it's the Unmarshaller responsibility to decide to cast that.)
tokenSlot.Type, tokenSlot.Int, tokenSlot.Float64, err = d.decodeNumber(majorByte)
return true, err
default:
return true, fmt.Errorf("Invalid byte while expecting start of value: 0x%x", majorByte)
}
}