~mna/zerojson

9815e26416ae791fd399d7f857f99c0e9cb22a3f — Martin Angers 1 year, 3 months ago 77434e3
peek, scan literal
2 files changed, 51 insertions(+), 29 deletions(-)

M zerojson.go
M zerojson_test.go
M zerojson.go => zerojson.go +33 -28
@@ 1,8 1,21 @@
package zerojson

import (
	"bytes"
	"fmt"
	"io"
)

// errorString allows a string constant to be an error.
type errorString string

func (e errorString) Error() string {
	return string(e)
}

const (
	// ErrIncompleteLiteral is the error representing an incomplete true, false or
	// null literal.
	ErrIncompleteLiteral errorString = "incomplete literal"
)

// JSON supports 7 different values:


@@ 74,7 87,7 @@ func (s *stack) push(v byte) {
}

func (s *stack) peek() byte {
	if s.cur > 0 {
	if s.cur > 0 || s.depth == 0 {
		return s.cur
	}



@@ 109,7 122,7 @@ type parser struct {
	// input is the data to parse
	input []byte
	// emit is called for each parsed tokens with the type of token, the
	// value and an error if the token is bad token. If the function returns
	// value and an error if the token is an invalid token. If the function returns
	// an error, the parsing stops, otherwise it continues with the next
	// token.
	//


@@ 121,11 134,11 @@ type parser struct {
	// 't' : true (v is the full literal)
	// 'f' : false (v is the full literal)
	// 'n' : null (v is the full literal)
	// '!' : bad token (v is the full bad token, e.g. an unclosed string
	//       will have a v from opening '"' to eof)
	// '\x00' : unknown or eof, only provided with a non-nil err
	//
	// The value v is a slice into the original input, it should not be
	// modified.
	// modified. If err is not nil, typ represents the type that it should
	// have been had it been valid.
	emit func(offset int, typ byte, v []byte, err error) error

	// parser state


@@ 147,22 160,18 @@ func (p *parser) parse() error {

		start := p.pos
		typ = p.cur
		switch p.cur {
		p.advance()
		switch typ {
		case '{':
			p.stack.push(p.cur)
			p.advance()

			p.stack.push(typ)
		case '[':
			p.stack.push(p.cur)
			p.advance()

			p.stack.push(typ)
		case '"':
			err = p.scanString()

			//err = p.scanString()
		case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
			first := typ
			typ = '1'
			err = p.scanNumber()

			//err = p.scanNumber(first)
		case 't':
			err = p.scanLiteral(trueTrail)
		case 'f':


@@ 171,27 180,23 @@ func (p *parser) parse() error {
			err = p.scanLiteral(nullTrail)

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

		if err != nil {
			typ = '!'
		}
		if e := p.emit(start, typ, p.input[start:p.pos], err); e != nil {
			return e
		}
	}
	return nil
	return p.emit(p.pos, p.cur, nil, io.EOF)
}

func (p *parser) scanLiteral(trail string) error {
	if !bytes.HasPrefix(p.input[p.pos:], []byte(trail)) {
		return ("nvalid character")
	for _, b := range []byte(trail) {
		if p.cur != b {
			return ErrIncompleteLiteral
		}
		p.advance()
	}

	p.pos += len(trail)
	p.advance()
	return nil
}


M zerojson_test.go => zerojson_test.go +18 -1
@@ 30,16 30,33 @@ func TestStack(t *testing.T) {
	for count := 0; count < 2; count++ {
		for _, v := range vals {
			s.push(v)
			b := s.peek()
			if b != v {
				t.Fatalf("peek: want %#U, got %#U", v, b)
			}
		}

		for i := len(vals) - 1; i >= 0; i-- {
			v := s.pop()
			if v != vals[i] {
				t.Fatalf("at %d: want %x, got %x", i, vals[i], v)
				t.Fatalf("pop at %d: want %#U, got %#U", i, vals[i], v)
			}

			if i > 0 {
				want := vals[i-1]
				for j := 0; j < 2; j++ {
					got := s.peek()
					if want != got {
						t.Fatalf("peek at %d: want %#U, got %#U", i, want, got)
					}
				}
			}
		}
		if s.depth != 0 {
			t.Fatalf("depth should be 0, is %d", s.depth)
		}
		if got := s.peek(); got != 0 {
			t.Fatalf("peek when empty should be 0, got %#U", got)
		}
	}
}