~mna/zerojson

2f03901dbdea79fbe34e68cad9974871fd0f26a0 — Martin Angers 1 year, 1 month ago 9815e26
scan and test literal tokens
2 files changed, 65 insertions(+), 6 deletions(-)

M zerojson.go
M zerojson_test.go
M zerojson.go => zerojson.go +13 -6
@@ 142,14 142,17 @@ type parser struct {
	emit func(offset int, typ byte, v []byte, err error) error

	// parser state
	cur    byte
	tok    byte // current token, '{', '[', '"', '1', 't', 'f', 'n'
	keyVal byte // when in an object, indicates if we're on key (':') or value (',')
	pos    int
	stack  stack
	cur   byte
	pos   int
	stack stack
}

func (p *parser) parse() error {
	// bootstrap execution
	p.pos = -1
	p.advance()

loop:
	for p.cur != eof {
		p.skipWhitespace()



@@ 161,6 164,7 @@ func (p *parser) parse() error {
		start := p.pos
		typ = p.cur
		p.advance()

		switch typ {
		case '{':
			p.stack.push(typ)


@@ 169,7 173,7 @@ func (p *parser) parse() error {
		case '"':
			//err = p.scanString()
		case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
			first := typ
			//first := typ
			typ = '1'
			//err = p.scanNumber(first)
		case 't':


@@ 178,6 182,9 @@ func (p *parser) parse() error {
			err = p.scanLiteral(falseTrail)
		case 'n':
			err = p.scanLiteral(nullTrail)
		case eof:
			// TODO: if a token was required, error
			break loop

		default:
			err = fmt.Errorf("invalid character: %#U", typ)

M zerojson_test.go => zerojson_test.go +52 -0
@@ 1,11 1,63 @@
package zerojson

import (
	"bytes"
	"fmt"
	"io"
	"math/rand"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
)

func TestParser(t *testing.T) {
	cases := []struct {
		in, out string
		err     error
	}{
		{"", "", nil},
		{" \t\n ", "", nil},
		{"null", "0: n: null", nil},
		{"true", "0: t: true", nil},
		{"false", "0: f: false", nil},
		{" null", "1: n: null", nil},
		{"\ttrue", "1: t: true", nil},
		{"\n false", "2: f: false", nil},
		{" null ", "1: n: null", nil},
		{"\ttrue\t", "1: t: true", nil},
		{"\n false\n ", "2: f: false", nil},
		{"nulltruefalse", "0: n: null\n4: t: true\n8: f: false", nil},
	}

	for _, c := range cases {
		t.Run(c.in, func(t *testing.T) {
			var buf bytes.Buffer

			p := parser{
				input: []byte(c.in),
				emit: func(offset int, typ byte, v []byte, err error) error {
					if err == io.EOF {
						return nil
					}
					fmt.Fprintf(&buf, "%d: %c: %s\n", offset, typ, string(v))
					return err
				},
			}
			err := p.parse()
			if c.err != nil {
				require.Error(t, err)
				require.Equal(t, c.err, err)
			} else {
				require.NoError(t, err)
			}

			require.Equal(t, strings.TrimSpace(c.out), strings.TrimSpace(buf.String()))
		})
	}
}

func TestStack(t *testing.T) {
	seed := time.Now().UnixNano()
	rnd := rand.New(rand.NewSource(seed))