internal/encoding/json: initial commit of JSON parser/serializer

Package json provides a parser and serializer for the JSON format.
This focuses on the grammar of the format and is agnostic towards specific
semantics of protobuf types.

High-level API:
	func Marshal(v Value, indent string) ([]byte, error)
	func Unmarshal(b []byte) (Value, error)
	type Type uint8
	    const Null Type ...
	type Value struct{ ... }
	    func ValueOf(v interface{}) Value
		func (v Value) Type() Type
		func (v Value) Bool() bool
		func (v Value) Number() float64
		func (v Value) String() string
		func (v Value) Array() []Value
		func (v Value) Object() [][2]Value
		func (v Value) Raw() []byte

Change-Id: I26422f6b3881ef1a11b8aa95160645b1384b27b8
Reviewed-on: https://go-review.googlesource.com/127824
Reviewed-by: Herbie Ong <herbie@google.com>
diff --git a/internal/encoding/json/number.go b/internal/encoding/json/number.go
new file mode 100644
index 0000000..7d27553
--- /dev/null
+++ b/internal/encoding/json/number.go
@@ -0,0 +1,79 @@
+// Copyright 2018 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 (
+	"io"
+	"math"
+	"regexp"
+	"strconv"
+
+	"google.golang.org/proto/internal/errors"
+)
+
+// marshalNumber encodes v as a Number.
+func (p *encoder) marshalNumber(v Value) error {
+	var err error
+	p.out, err = appendNumber(p.out, v)
+	return err
+}
+func appendNumber(out []byte, v Value) ([]byte, error) {
+	if v.Type() != Number {
+		return nil, errors.New("invalid type %v, expected number", v.Type())
+	}
+	if len(v.raw) > 0 {
+		return append(out, v.raw...), nil
+	}
+	n := v.Number()
+	if math.IsInf(n, 0) || math.IsNaN(n) {
+		return nil, errors.New("invalid number value: %v", n)
+	}
+
+	// JSON number formatting logic based on encoding/json.
+	// See floatEncoder.encode for reference.
+	bits := 64
+	if float64(float32(n)) == n {
+		bits = 32
+	}
+	fmt := byte('f')
+	if abs := math.Abs(n); abs != 0 {
+		if bits == 64 && (abs < 1e-6 || abs >= 1e21) || bits == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) {
+			fmt = 'e'
+		}
+	}
+	out = strconv.AppendFloat(out, n, fmt, -1, bits)
+	if fmt == 'e' {
+		n := len(out)
+		if n >= 4 && out[n-4] == 'e' && out[n-3] == '-' && out[n-2] == '0' {
+			out[n-2] = out[n-1]
+			out = out[:n-1]
+		}
+	}
+	return out, nil
+}
+
+// Exact expression to match a JSON floating-point number.
+// JSON's grammar for floats is more restrictive than Go's grammar.
+var floatRegexp = regexp.MustCompile("^-?(0|[1-9][0-9]*)([.][0-9]+)?([eE][+-]?[0-9]+)?")
+
+// unmarshalNumber decodes a Number from the input.
+func (p *decoder) unmarshalNumber() (Value, error) {
+	v, n, err := consumeNumber(p.in)
+	p.consume(n)
+	return v, err
+}
+func consumeNumber(in []byte) (Value, int, error) {
+	if len(in) == 0 {
+		return Value{}, 0, io.ErrUnexpectedEOF
+	}
+	if n := matchWithDelim(floatRegexp, in); n > 0 {
+		v, err := strconv.ParseFloat(string(in[:n]), 64)
+		if err != nil {
+			return Value{}, 0, err
+		}
+		return rawValueOf(v, in[:n:n]), n, nil
+	}
+	return Value{}, 0, newSyntaxError("invalid %q as number", errRegexp.Find(in))
+}