encoding/protojson: refactor to follow prototext pattern

All unmarshaling error messages now contain line number and column
information, except for the following errors:
- `unexpected EOF`
- `no support for proto1 MessageSets`
- `required fields X not set`

Changes to internal/encoding/json:
- Moved encoding funcs in string.go and number.go into encode.go.
- Separated out encoding kind constants from decoding ones.
- Renamed file string.go to decode_string.go.
- Renamed file number.go to decode_number.go.
- Renamed Type struct to Kind.
- Renamed Value struct to Token.
- Token accessor methods no longer return error.
  Name, Bool, ParsedString will panic if called on the wrong kind.
  Float, Int, Uint has ok bool result to check against.
- Changed Peek to return Token and error.

Changes to encoding/protojson:
- Updated internal/encoding/json API calls.
- Added line info on most unmarshaling error messages and kept
  description simple and consistent.

Change-Id: Ie50456694f2214c5c4fafd2c9b9239680da0deec
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/218978
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/encoding/protojson/decode.go b/encoding/protojson/decode.go
index db8a3df..4d13d77 100644
--- a/encoding/protojson/decode.go
+++ b/encoding/protojson/decode.go
@@ -45,8 +45,6 @@
 		protoregistry.MessageTypeResolver
 		protoregistry.ExtensionTypeResolver
 	}
-
-	decoder *json.Decoder
 }
 
 // Unmarshal reads the given []byte and populates the given proto.Message using
@@ -59,19 +57,19 @@
 	if o.Resolver == nil {
 		o.Resolver = protoregistry.GlobalTypes
 	}
-	o.decoder = json.NewDecoder(b)
 
-	if err := o.unmarshalMessage(m.ProtoReflect(), false); err != nil {
+	dec := decoder{json.NewDecoder(b), o}
+	if err := dec.unmarshalMessage(m.ProtoReflect(), false); err != nil {
 		return err
 	}
 
 	// Check for EOF.
-	val, err := o.decoder.Read()
+	tok, err := dec.Read()
 	if err != nil {
 		return err
 	}
-	if val.Type() != json.EOF {
-		return unexpectedJSONError{val}
+	if tok.Kind() != json.EOF {
+		return dec.unexpectedTokenError(tok)
 	}
 
 	if o.AllowPartial {
@@ -80,53 +78,45 @@
 	return proto.IsInitialized(m)
 }
 
-// unexpectedJSONError is an error that contains the unexpected json.Value. This
-// is returned by methods to provide callers the read json.Value that it did not
-// expect.
-// TODO: Consider moving this to internal/encoding/json for consistency with
-// errors that package returns.
-type unexpectedJSONError struct {
-	value json.Value
+type decoder struct {
+	*json.Decoder
+	opts UnmarshalOptions
 }
 
-func (e unexpectedJSONError) Error() string {
-	return newError("unexpected value %s", e.value).Error()
+// newError returns an error object with position info.
+func (d decoder) newError(pos int, f string, x ...interface{}) error {
+	line, column := d.Position(pos)
+	head := fmt.Sprintf("(line %d:%d): ", line, column)
+	return errors.New(head+f, x...)
 }
 
-// newError returns an error object. If one of the values passed in is of
-// json.Value type, it produces an error with position info.
-func newError(f string, x ...interface{}) error {
-	var hasValue bool
-	var line, column int
-	for i := 0; i < len(x); i++ {
-		if val, ok := x[i].(json.Value); ok {
-			line, column = val.Position()
-			hasValue = true
-			break
-		}
-	}
-	e := errors.New(f, x...)
-	if hasValue {
-		return errors.New("(line %d:%d): %v", line, column, e)
-	}
-	return e
+// unexpectedTokenError returns a syntax error for the given unexpected token.
+func (d decoder) unexpectedTokenError(tok json.Token) error {
+	return d.syntaxError(tok.Pos(), "unexpected token %s", tok.RawString())
+}
+
+// syntaxError returns a syntax error for given position.
+func (d decoder) syntaxError(pos int, f string, x ...interface{}) error {
+	line, column := d.Position(pos)
+	head := fmt.Sprintf("syntax error (line %d:%d): ", line, column)
+	return errors.New(head+f, x...)
 }
 
 // unmarshalMessage unmarshals a message into the given protoreflect.Message.
-func (o UnmarshalOptions) unmarshalMessage(m pref.Message, skipTypeURL bool) error {
+func (d decoder) unmarshalMessage(m pref.Message, skipTypeURL bool) error {
 	if isCustomType(m.Descriptor().FullName()) {
-		return o.unmarshalCustomType(m)
+		return d.unmarshalCustomType(m)
 	}
 
-	jval, err := o.decoder.Read()
+	tok, err := d.Read()
 	if err != nil {
 		return err
 	}
-	if jval.Type() != json.StartObject {
-		return unexpectedJSONError{jval}
+	if tok.Kind() != json.ObjectOpen {
+		return d.unexpectedTokenError(tok)
 	}
 
-	if err := o.unmarshalFields(m, skipTypeURL); err != nil {
+	if err := d.unmarshalFields(m, skipTypeURL); err != nil {
 		return err
 	}
 
@@ -134,7 +124,7 @@
 }
 
 // unmarshalFields unmarshals the fields into the given protoreflect.Message.
-func (o UnmarshalOptions) unmarshalFields(m pref.Message, skipTypeURL bool) error {
+func (d decoder) unmarshalFields(m pref.Message, skipTypeURL bool) error {
 	messageDesc := m.Descriptor()
 	if !flags.ProtoLegacy && messageset.IsMessageSet(messageDesc) {
 		return errors.New("no support for proto1 MessageSets")
@@ -145,28 +135,25 @@
 	fieldDescs := messageDesc.Fields()
 	for {
 		// Read field name.
-		jval, err := o.decoder.Read()
+		tok, err := d.Read()
 		if err != nil {
 			return err
 		}
-		switch jval.Type() {
+		switch tok.Kind() {
 		default:
-			return unexpectedJSONError{jval}
-		case json.EndObject:
+			return d.unexpectedTokenError(tok)
+		case json.ObjectClose:
 			return nil
 		case json.Name:
 			// Continue below.
 		}
 
-		name, err := jval.Name()
-		if err != nil {
-			return err
-		}
+		name := tok.Name()
 		// Unmarshaling a non-custom embedded message in Any will contain the
 		// JSON field "@type" which should be skipped because it is not a field
 		// of the embedded message, but simply an artifact of the Any format.
 		if skipTypeURL && name == "@type" {
-			o.decoder.Read()
+			d.Read()
 			continue
 		}
 
@@ -175,14 +162,14 @@
 		if strings.HasPrefix(name, "[") && strings.HasSuffix(name, "]") {
 			// Only extension names are in [name] format.
 			extName := pref.FullName(name[1 : len(name)-1])
-			extType, err := o.findExtension(extName)
+			extType, err := d.findExtension(extName)
 			if err != nil && err != protoregistry.NotFound {
-				return errors.New("unable to resolve [%v]: %v", extName, err)
+				return d.newError(tok.Pos(), "unable to resolve %s: %v", tok.RawString(), err)
 			}
 			if extType != nil {
 				fd = extType.TypeDescriptor()
 				if !messageDesc.ExtensionRanges().Has(fd.Number()) || fd.ContainingMessage().FullName() != messageDesc.FullName() {
-					return errors.New("message %v cannot be extended by %v", messageDesc.FullName(), fd.FullName())
+					return d.newError(tok.Pos(), "message %v cannot be extended by %v", messageDesc.FullName(), fd.FullName())
 				}
 			}
 		} else {
@@ -210,65 +197,65 @@
 
 		if fd == nil {
 			// Field is unknown.
-			if o.DiscardUnknown {
-				if err := skipJSONValue(o.decoder); err != nil {
+			if d.opts.DiscardUnknown {
+				if err := d.skipJSONValue(); err != nil {
 					return err
 				}
 				continue
 			}
-			return newError("%v contains unknown field %s", messageDesc.FullName(), jval)
+			return d.newError(tok.Pos(), "unknown field %v", tok.RawString())
 		}
 
 		// Do not allow duplicate fields.
 		num := uint64(fd.Number())
 		if seenNums.Has(num) {
-			return newError("%v contains repeated field %s", messageDesc.FullName(), jval)
+			return d.newError(tok.Pos(), "duplicate field %v", tok.RawString())
 		}
 		seenNums.Set(num)
 
 		// No need to set values for JSON null unless the field type is
 		// google.protobuf.Value or google.protobuf.NullValue.
-		if o.decoder.Peek() == json.Null && !isKnownValue(fd) && !isNullValue(fd) {
-			o.decoder.Read()
+		if tok, _ := d.Peek(); tok.Kind() == json.Null && !isKnownValue(fd) && !isNullValue(fd) {
+			d.Read()
 			continue
 		}
 
 		switch {
 		case fd.IsList():
 			list := m.Mutable(fd).List()
-			if err := o.unmarshalList(list, fd); err != nil {
-				return errors.New("%v|%q: %v", fd.FullName(), name, err)
+			if err := d.unmarshalList(list, fd); err != nil {
+				return err
 			}
 		case fd.IsMap():
 			mmap := m.Mutable(fd).Map()
-			if err := o.unmarshalMap(mmap, fd); err != nil {
-				return errors.New("%v|%q: %v", fd.FullName(), name, err)
+			if err := d.unmarshalMap(mmap, fd); err != nil {
+				return err
 			}
 		default:
 			// If field is a oneof, check if it has already been set.
 			if od := fd.ContainingOneof(); od != nil {
 				idx := uint64(od.Index())
 				if seenOneofs.Has(idx) {
-					return errors.New("%v: oneof is already set", od.FullName())
+					return d.newError(tok.Pos(), "error parsing %s, oneof %v is already set", tok.RawString(), od.FullName())
 				}
 				seenOneofs.Set(idx)
 			}
 
 			// Required or optional fields.
-			if err := o.unmarshalSingular(m, fd); err != nil {
-				return errors.New("%v|%q: %v", fd.FullName(), name, err)
+			if err := d.unmarshalSingular(m, fd); err != nil {
+				return err
 			}
 		}
 	}
 }
 
 // findExtension returns protoreflect.ExtensionType from the resolver if found.
-func (o UnmarshalOptions) findExtension(xtName pref.FullName) (pref.ExtensionType, error) {
-	xt, err := o.Resolver.FindExtensionByName(xtName)
+func (d decoder) findExtension(xtName pref.FullName) (pref.ExtensionType, error) {
+	xt, err := d.opts.Resolver.FindExtensionByName(xtName)
 	if err == nil {
 		return xt, nil
 	}
-	return messageset.FindMessageSetExtension(o.Resolver, xtName)
+	return messageset.FindMessageSetExtension(d.opts.Resolver, xtName)
 }
 
 func isKnownValue(fd pref.FieldDescriptor) bool {
@@ -281,17 +268,17 @@
 	return ed != nil && ed.FullName() == "google.protobuf.NullValue"
 }
 
-// unmarshalSingular unmarshals to the non-repeated field specified by the given
-// FieldDescriptor.
-func (o UnmarshalOptions) unmarshalSingular(m pref.Message, fd pref.FieldDescriptor) error {
+// unmarshalSingular unmarshals to the non-repeated field specified
+// by the given FieldDescriptor.
+func (d decoder) unmarshalSingular(m pref.Message, fd pref.FieldDescriptor) error {
 	var val pref.Value
 	var err error
 	switch fd.Kind() {
 	case pref.MessageKind, pref.GroupKind:
 		val = m.NewField(fd)
-		err = o.unmarshalMessage(val.Message(), false)
+		err = d.unmarshalMessage(val.Message(), false)
 	default:
-		val, err = o.unmarshalScalar(fd)
+		val, err = d.unmarshalScalar(fd)
 	}
 
 	if err != nil {
@@ -303,11 +290,11 @@
 
 // unmarshalScalar unmarshals to a scalar/enum protoreflect.Value specified by
 // the given FieldDescriptor.
-func (o UnmarshalOptions) unmarshalScalar(fd pref.FieldDescriptor) (pref.Value, error) {
+func (d decoder) unmarshalScalar(fd pref.FieldDescriptor) (pref.Value, error) {
 	const b32 int = 32
 	const b64 int = 64
 
-	jval, err := o.decoder.Read()
+	tok, err := d.Read()
 	if err != nil {
 		return pref.Value{}, err
 	}
@@ -315,177 +302,182 @@
 	kind := fd.Kind()
 	switch kind {
 	case pref.BoolKind:
-		return unmarshalBool(jval)
+		if tok.Kind() == json.Bool {
+			return pref.ValueOfBool(tok.Bool()), nil
+		}
 
 	case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
-		return unmarshalInt(jval, b32)
+		if v, ok := unmarshalInt(tok, b32); ok {
+			return v, nil
+		}
 
 	case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
-		return unmarshalInt(jval, b64)
+		if v, ok := unmarshalInt(tok, b64); ok {
+			return v, nil
+		}
 
 	case pref.Uint32Kind, pref.Fixed32Kind:
-		return unmarshalUint(jval, b32)
+		if v, ok := unmarshalUint(tok, b32); ok {
+			return v, nil
+		}
 
 	case pref.Uint64Kind, pref.Fixed64Kind:
-		return unmarshalUint(jval, b64)
+		if v, ok := unmarshalUint(tok, b64); ok {
+			return v, nil
+		}
 
 	case pref.FloatKind:
-		return unmarshalFloat(jval, b32)
+		if v, ok := unmarshalFloat(tok, b32); ok {
+			return v, nil
+		}
 
 	case pref.DoubleKind:
-		return unmarshalFloat(jval, b64)
+		if v, ok := unmarshalFloat(tok, b64); ok {
+			return v, nil
+		}
 
 	case pref.StringKind:
-		pval, err := unmarshalString(jval)
-		if err != nil {
-			return pval, err
+		if tok.Kind() == json.String {
+			return pref.ValueOfString(tok.ParsedString()), nil
 		}
-		return pval, nil
 
 	case pref.BytesKind:
-		return unmarshalBytes(jval)
+		if v, ok := unmarshalBytes(tok); ok {
+			return v, nil
+		}
 
 	case pref.EnumKind:
-		return unmarshalEnum(jval, fd)
+		if v, ok := unmarshalEnum(tok, fd); ok {
+			return v, nil
+		}
+
+	default:
+		panic(fmt.Sprintf("unmarshalScalar: invalid scalar kind %v", kind))
 	}
 
-	panic(fmt.Sprintf("invalid scalar kind %v", kind))
+	return pref.Value{}, d.newError(tok.Pos(), "invalid value for %v type: %v", kind, tok.RawString())
 }
 
-func unmarshalBool(jval json.Value) (pref.Value, error) {
-	if jval.Type() != json.Bool {
-		return pref.Value{}, unexpectedJSONError{jval}
-	}
-	b, err := jval.Bool()
-	return pref.ValueOfBool(b), err
-}
-
-func unmarshalInt(jval json.Value, bitSize int) (pref.Value, error) {
-	switch jval.Type() {
+func unmarshalInt(tok json.Token, bitSize int) (pref.Value, bool) {
+	switch tok.Kind() {
 	case json.Number:
-		return getInt(jval, bitSize)
+		return getInt(tok, bitSize)
 
 	case json.String:
 		// Decode number from string.
-		s := strings.TrimSpace(jval.String())
-		if len(s) != len(jval.String()) {
-			return pref.Value{}, errors.New("invalid number %v", jval.Raw())
+		s := strings.TrimSpace(tok.ParsedString())
+		if len(s) != len(tok.ParsedString()) {
+			return pref.Value{}, false
 		}
 		dec := json.NewDecoder([]byte(s))
-		jval, err := dec.Read()
+		tok, err := dec.Read()
 		if err != nil {
-			return pref.Value{}, err
+			return pref.Value{}, false
 		}
-		return getInt(jval, bitSize)
+		return getInt(tok, bitSize)
 	}
-	return pref.Value{}, unexpectedJSONError{jval}
+	return pref.Value{}, false
 }
 
-func getInt(jval json.Value, bitSize int) (pref.Value, error) {
-	n, err := jval.Int(bitSize)
-	if err != nil {
-		return pref.Value{}, err
+func getInt(tok json.Token, bitSize int) (pref.Value, bool) {
+	n, ok := tok.Int(bitSize)
+	if !ok {
+		return pref.Value{}, false
 	}
 	if bitSize == 32 {
-		return pref.ValueOfInt32(int32(n)), nil
+		return pref.ValueOfInt32(int32(n)), true
 	}
-	return pref.ValueOfInt64(n), nil
+	return pref.ValueOfInt64(n), true
 }
 
-func unmarshalUint(jval json.Value, bitSize int) (pref.Value, error) {
-	switch jval.Type() {
+func unmarshalUint(tok json.Token, bitSize int) (pref.Value, bool) {
+	switch tok.Kind() {
 	case json.Number:
-		return getUint(jval, bitSize)
+		return getUint(tok, bitSize)
 
 	case json.String:
 		// Decode number from string.
-		s := strings.TrimSpace(jval.String())
-		if len(s) != len(jval.String()) {
-			return pref.Value{}, errors.New("invalid number %v", jval.Raw())
+		s := strings.TrimSpace(tok.ParsedString())
+		if len(s) != len(tok.ParsedString()) {
+			return pref.Value{}, false
 		}
 		dec := json.NewDecoder([]byte(s))
-		jval, err := dec.Read()
+		tok, err := dec.Read()
 		if err != nil {
-			return pref.Value{}, err
+			return pref.Value{}, false
 		}
-		return getUint(jval, bitSize)
+		return getUint(tok, bitSize)
 	}
-	return pref.Value{}, unexpectedJSONError{jval}
+	return pref.Value{}, false
 }
 
-func getUint(jval json.Value, bitSize int) (pref.Value, error) {
-	n, err := jval.Uint(bitSize)
-	if err != nil {
-		return pref.Value{}, err
+func getUint(tok json.Token, bitSize int) (pref.Value, bool) {
+	n, ok := tok.Uint(bitSize)
+	if !ok {
+		return pref.Value{}, false
 	}
 	if bitSize == 32 {
-		return pref.ValueOfUint32(uint32(n)), nil
+		return pref.ValueOfUint32(uint32(n)), true
 	}
-	return pref.ValueOfUint64(n), nil
+	return pref.ValueOfUint64(n), true
 }
 
-func unmarshalFloat(jval json.Value, bitSize int) (pref.Value, error) {
-	switch jval.Type() {
+func unmarshalFloat(tok json.Token, bitSize int) (pref.Value, bool) {
+	switch tok.Kind() {
 	case json.Number:
-		return getFloat(jval, bitSize)
+		return getFloat(tok, bitSize)
 
 	case json.String:
-		s := jval.String()
+		s := tok.ParsedString()
 		switch s {
 		case "NaN":
 			if bitSize == 32 {
-				return pref.ValueOfFloat32(float32(math.NaN())), nil
+				return pref.ValueOfFloat32(float32(math.NaN())), true
 			}
-			return pref.ValueOfFloat64(math.NaN()), nil
+			return pref.ValueOfFloat64(math.NaN()), true
 		case "Infinity":
 			if bitSize == 32 {
-				return pref.ValueOfFloat32(float32(math.Inf(+1))), nil
+				return pref.ValueOfFloat32(float32(math.Inf(+1))), true
 			}
-			return pref.ValueOfFloat64(math.Inf(+1)), nil
+			return pref.ValueOfFloat64(math.Inf(+1)), true
 		case "-Infinity":
 			if bitSize == 32 {
-				return pref.ValueOfFloat32(float32(math.Inf(-1))), nil
+				return pref.ValueOfFloat32(float32(math.Inf(-1))), true
 			}
-			return pref.ValueOfFloat64(math.Inf(-1)), nil
+			return pref.ValueOfFloat64(math.Inf(-1)), true
 		}
+
 		// Decode number from string.
 		if len(s) != len(strings.TrimSpace(s)) {
-			return pref.Value{}, errors.New("invalid number %v", jval.Raw())
+			return pref.Value{}, false
 		}
 		dec := json.NewDecoder([]byte(s))
-		jval, err := dec.Read()
+		tok, err := dec.Read()
 		if err != nil {
-			return pref.Value{}, err
+			return pref.Value{}, false
 		}
-		return getFloat(jval, bitSize)
+		return getFloat(tok, bitSize)
 	}
-	return pref.Value{}, unexpectedJSONError{jval}
+	return pref.Value{}, false
 }
 
-func getFloat(jval json.Value, bitSize int) (pref.Value, error) {
-	n, err := jval.Float(bitSize)
-	if err != nil {
-		return pref.Value{}, err
+func getFloat(tok json.Token, bitSize int) (pref.Value, bool) {
+	n, ok := tok.Float(bitSize)
+	if !ok {
+		return pref.Value{}, false
 	}
 	if bitSize == 32 {
-		return pref.ValueOfFloat32(float32(n)), nil
+		return pref.ValueOfFloat32(float32(n)), true
 	}
-	return pref.ValueOfFloat64(n), nil
+	return pref.ValueOfFloat64(n), true
 }
 
-func unmarshalString(jval json.Value) (pref.Value, error) {
-	if jval.Type() != json.String {
-		return pref.Value{}, unexpectedJSONError{jval}
-	}
-	return pref.ValueOfString(jval.String()), nil
-}
-
-func unmarshalBytes(jval json.Value) (pref.Value, error) {
-	if jval.Type() != json.String {
-		return pref.Value{}, unexpectedJSONError{jval}
+func unmarshalBytes(tok json.Token) (pref.Value, bool) {
+	if tok.Kind() != json.String {
+		return pref.Value{}, false
 	}
 
-	s := jval.String()
+	s := tok.ParsedString()
 	enc := base64.StdEncoding
 	if strings.ContainsAny(s, "-_") {
 		enc = base64.URLEncoding
@@ -495,88 +487,93 @@
 	}
 	b, err := enc.DecodeString(s)
 	if err != nil {
-		return pref.Value{}, err
+		return pref.Value{}, false
 	}
-	return pref.ValueOfBytes(b), nil
+	return pref.ValueOfBytes(b), true
 }
 
-func unmarshalEnum(jval json.Value, fd pref.FieldDescriptor) (pref.Value, error) {
-	switch jval.Type() {
+func unmarshalEnum(tok json.Token, fd pref.FieldDescriptor) (pref.Value, bool) {
+	switch tok.Kind() {
 	case json.String:
 		// Lookup EnumNumber based on name.
-		s := jval.String()
+		s := tok.ParsedString()
 		if enumVal := fd.Enum().Values().ByName(pref.Name(s)); enumVal != nil {
-			return pref.ValueOfEnum(enumVal.Number()), nil
+			return pref.ValueOfEnum(enumVal.Number()), true
 		}
-		return pref.Value{}, newError("invalid enum value %q", jval)
 
 	case json.Number:
-		n, err := jval.Int(32)
-		if err != nil {
-			return pref.Value{}, err
+		if n, ok := tok.Int(32); ok {
+			return pref.ValueOfEnum(pref.EnumNumber(n)), true
 		}
-		return pref.ValueOfEnum(pref.EnumNumber(n)), nil
 
 	case json.Null:
 		// This is only valid for google.protobuf.NullValue.
 		if isNullValue(fd) {
-			return pref.ValueOfEnum(0), nil
+			return pref.ValueOfEnum(0), true
 		}
 	}
 
-	return pref.Value{}, unexpectedJSONError{jval}
+	return pref.Value{}, false
 }
 
-func (o UnmarshalOptions) unmarshalList(list pref.List, fd pref.FieldDescriptor) error {
-	jval, err := o.decoder.Read()
+func (d decoder) unmarshalList(list pref.List, fd pref.FieldDescriptor) error {
+	tok, err := d.Read()
 	if err != nil {
 		return err
 	}
-	if jval.Type() != json.StartArray {
-		return unexpectedJSONError{jval}
+	if tok.Kind() != json.ArrayOpen {
+		return d.unexpectedTokenError(tok)
 	}
 
 	switch fd.Kind() {
 	case pref.MessageKind, pref.GroupKind:
 		for {
-			val := list.NewElement()
-			err := o.unmarshalMessage(val.Message(), false)
+			tok, err := d.Peek()
 			if err != nil {
-				if e, ok := err.(unexpectedJSONError); ok {
-					if e.value.Type() == json.EndArray {
-						// Done with list.
-						return nil
-					}
-				}
+				return err
+			}
+
+			if tok.Kind() == json.ArrayClose {
+				d.Read()
+				return nil
+			}
+
+			val := list.NewElement()
+			if err := d.unmarshalMessage(val.Message(), false); err != nil {
 				return err
 			}
 			list.Append(val)
 		}
 	default:
 		for {
-			val, err := o.unmarshalScalar(fd)
+			tok, err := d.Peek()
 			if err != nil {
-				if e, ok := err.(unexpectedJSONError); ok {
-					if e.value.Type() == json.EndArray {
-						// Done with list.
-						return nil
-					}
-				}
+				return err
+			}
+
+			if tok.Kind() == json.ArrayClose {
+				d.Read()
+				return nil
+			}
+
+			val, err := d.unmarshalScalar(fd)
+			if err != nil {
 				return err
 			}
 			list.Append(val)
 		}
 	}
+
 	return nil
 }
 
-func (o UnmarshalOptions) unmarshalMap(mmap pref.Map, fd pref.FieldDescriptor) error {
-	jval, err := o.decoder.Read()
+func (d decoder) unmarshalMap(mmap pref.Map, fd pref.FieldDescriptor) error {
+	tok, err := d.Read()
 	if err != nil {
 		return err
 	}
-	if jval.Type() != json.StartObject {
-		return unexpectedJSONError{jval}
+	if tok.Kind() != json.ObjectOpen {
+		return d.unexpectedTokenError(tok)
 	}
 
 	// Determine ahead whether map entry is a scalar type or a message type in
@@ -587,47 +584,42 @@
 	case pref.MessageKind, pref.GroupKind:
 		unmarshalMapValue = func() (pref.Value, error) {
 			val := mmap.NewValue()
-			if err := o.unmarshalMessage(val.Message(), false); err != nil {
+			if err := d.unmarshalMessage(val.Message(), false); err != nil {
 				return pref.Value{}, err
 			}
 			return val, nil
 		}
 	default:
 		unmarshalMapValue = func() (pref.Value, error) {
-			return o.unmarshalScalar(fd.MapValue())
+			return d.unmarshalScalar(fd.MapValue())
 		}
 	}
 
 Loop:
 	for {
 		// Read field name.
-		jval, err := o.decoder.Read()
+		tok, err := d.Read()
 		if err != nil {
 			return err
 		}
-		switch jval.Type() {
+		switch tok.Kind() {
 		default:
-			return unexpectedJSONError{jval}
-		case json.EndObject:
+			return d.unexpectedTokenError(tok)
+		case json.ObjectClose:
 			break Loop
 		case json.Name:
 			// Continue.
 		}
 
-		name, err := jval.Name()
-		if err != nil {
-			return err
-		}
-
 		// Unmarshal field name.
-		pkey, err := unmarshalMapKey(name, fd.MapKey())
+		pkey, err := d.unmarshalMapKey(tok, fd.MapKey())
 		if err != nil {
 			return err
 		}
 
 		// Check for duplicate field name.
 		if mmap.Has(pkey) {
-			return newError("duplicate map key %q", jval)
+			return d.newError(tok.Pos(), "duplicate map key %v", tok.RawString())
 		}
 
 		// Read and unmarshal field value.
@@ -642,13 +634,14 @@
 	return nil
 }
 
-// unmarshalMapKey converts given string into a protoreflect.MapKey. A map key type is any
-// integral or string type.
-func unmarshalMapKey(name string, fd pref.FieldDescriptor) (pref.MapKey, error) {
+// unmarshalMapKey converts given token of Name kind into a protoreflect.MapKey.
+// A map key type is any integral or string type.
+func (d decoder) unmarshalMapKey(tok json.Token, fd pref.FieldDescriptor) (pref.MapKey, error) {
 	const b32 = 32
 	const b64 = 64
 	const base10 = 10
 
+	name := tok.Name()
 	kind := fd.Kind()
 	switch kind {
 	case pref.StringKind:
@@ -661,36 +654,30 @@
 		case "false":
 			return pref.ValueOfBool(false).MapKey(), nil
 		}
-		return pref.MapKey{}, errors.New("invalid value for boolean key %q", name)
 
 	case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
-		n, err := strconv.ParseInt(name, base10, b32)
-		if err != nil {
-			return pref.MapKey{}, err
+		if n, err := strconv.ParseInt(name, base10, b32); err == nil {
+			return pref.ValueOfInt32(int32(n)).MapKey(), nil
 		}
-		return pref.ValueOfInt32(int32(n)).MapKey(), nil
 
 	case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
-		n, err := strconv.ParseInt(name, base10, b64)
-		if err != nil {
-			return pref.MapKey{}, err
+		if n, err := strconv.ParseInt(name, base10, b64); err == nil {
+			return pref.ValueOfInt64(int64(n)).MapKey(), nil
 		}
-		return pref.ValueOfInt64(int64(n)).MapKey(), nil
 
 	case pref.Uint32Kind, pref.Fixed32Kind:
-		n, err := strconv.ParseUint(name, base10, b32)
-		if err != nil {
-			return pref.MapKey{}, err
+		if n, err := strconv.ParseUint(name, base10, b32); err == nil {
+			return pref.ValueOfUint32(uint32(n)).MapKey(), nil
 		}
-		return pref.ValueOfUint32(uint32(n)).MapKey(), nil
 
 	case pref.Uint64Kind, pref.Fixed64Kind:
-		n, err := strconv.ParseUint(name, base10, b64)
-		if err != nil {
-			return pref.MapKey{}, err
+		if n, err := strconv.ParseUint(name, base10, b64); err == nil {
+			return pref.ValueOfUint64(uint64(n)).MapKey(), nil
 		}
-		return pref.ValueOfUint64(uint64(n)).MapKey(), nil
+
+	default:
+		panic(fmt.Sprintf("invalid kind for map key: %v", kind))
 	}
 
-	panic(fmt.Sprintf("%s: invalid kind %s for map key", fd.FullName(), kind))
+	return pref.MapKey{}, d.newError(tok.Pos(), "invalid value for %v key: %s", kind, tok.RawString())
 }