Skip to content

Commit 0a4c85f

Browse files
author
Tao Wen
committed
basic iterator
1 parent 54cfb9f commit 0a4c85f

File tree

9 files changed

+1498
-0
lines changed

9 files changed

+1498
-0
lines changed

go.mod

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module github.com/json-iterator/tinygo
2+
3+
go 1.12
4+
5+
require (
6+
)

iter.go

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
package jsoniter
2+
3+
import (
4+
"fmt"
5+
"io"
6+
)
7+
8+
// ValueType the type for JSON element
9+
type ValueType int
10+
11+
const (
12+
// InvalidValue invalid JSON element
13+
InvalidValue ValueType = iota
14+
// StringValue JSON element "string"
15+
StringValue
16+
// NumberValue JSON element 100 or 0.10
17+
NumberValue
18+
// NilValue JSON element null
19+
NilValue
20+
// BoolValue JSON element true or false
21+
BoolValue
22+
// ArrayValue JSON element []
23+
ArrayValue
24+
// ObjectValue JSON element {}
25+
ObjectValue
26+
)
27+
const uint32SafeToMultiply10 = uint32(0xffffffff)/10 - 1
28+
const uint64SafeToMultiple10 = uint64(0xffffffffffffffff)/10 - 1
29+
const maxFloat64 = 1<<53 - 1
30+
31+
var pow10 []uint64
32+
var hexDigits []byte
33+
var valueTypes []ValueType
34+
35+
func init() {
36+
pow10 = []uint64{1, 10, 100, 1000, 10000, 100000, 1000000}
37+
hexDigits = make([]byte, 256)
38+
for i := 0; i < len(hexDigits); i++ {
39+
hexDigits[i] = 255
40+
}
41+
for i := '0'; i <= '9'; i++ {
42+
hexDigits[i] = byte(i - '0')
43+
}
44+
for i := 'a'; i <= 'f'; i++ {
45+
hexDigits[i] = byte((i - 'a') + 10)
46+
}
47+
for i := 'A'; i <= 'F'; i++ {
48+
hexDigits[i] = byte((i - 'A') + 10)
49+
}
50+
valueTypes = make([]ValueType, 256)
51+
for i := 0; i < len(valueTypes); i++ {
52+
valueTypes[i] = InvalidValue
53+
}
54+
valueTypes['"'] = StringValue
55+
valueTypes['-'] = NumberValue
56+
valueTypes['0'] = NumberValue
57+
valueTypes['1'] = NumberValue
58+
valueTypes['2'] = NumberValue
59+
valueTypes['3'] = NumberValue
60+
valueTypes['4'] = NumberValue
61+
valueTypes['5'] = NumberValue
62+
valueTypes['6'] = NumberValue
63+
valueTypes['7'] = NumberValue
64+
valueTypes['8'] = NumberValue
65+
valueTypes['9'] = NumberValue
66+
valueTypes['t'] = BoolValue
67+
valueTypes['f'] = BoolValue
68+
valueTypes['n'] = NilValue
69+
valueTypes['['] = ArrayValue
70+
valueTypes['{'] = ObjectValue
71+
}
72+
73+
// Iterator is a io.Reader like object, with JSON specific read functions.
74+
// Error is not returned as return value, but stored as Error member on this iterator instance.
75+
type Iterator struct {
76+
buf []byte
77+
head int
78+
Error error
79+
}
80+
81+
// ParseBytes creates an Iterator instance from byte array
82+
func ParseBytes(input []byte) *Iterator {
83+
return &Iterator{
84+
buf: input,
85+
head: 0,
86+
}
87+
}
88+
89+
// WhatIsNext gets ValueType of relatively next json element
90+
func (iter *Iterator) WhatIsNext() ValueType {
91+
valueType := valueTypes[iter.nextToken()]
92+
iter.unreadByte()
93+
return valueType
94+
}
95+
96+
func (iter *Iterator) skipWhitespacesWithoutLoadMore() bool {
97+
for i := iter.head; i < len(iter.buf); i++ {
98+
c := iter.buf[i]
99+
switch c {
100+
case ' ', '\n', '\t', '\r':
101+
continue
102+
}
103+
iter.head = i
104+
return false
105+
}
106+
return true
107+
}
108+
109+
func (iter *Iterator) isObjectEnd() bool {
110+
c := iter.nextToken()
111+
if c == ',' {
112+
return false
113+
}
114+
if c == '}' {
115+
return true
116+
}
117+
iter.ReportError("isObjectEnd", "object ended prematurely, unexpected char "+string([]byte{c}))
118+
return true
119+
}
120+
121+
// ReportError record a error in iterator instance with current position.
122+
func (iter *Iterator) ReportError(operation string, msg string) {
123+
if iter.Error != nil {
124+
if iter.Error != io.EOF {
125+
return
126+
}
127+
}
128+
peekStart := iter.head - 10
129+
if peekStart < 0 {
130+
peekStart = 0
131+
}
132+
peekEnd := iter.head + 10
133+
if peekEnd > len(iter.buf) {
134+
peekEnd = len(iter.buf)
135+
}
136+
parsing := string(iter.buf[peekStart:peekEnd])
137+
contextStart := iter.head - 50
138+
if contextStart < 0 {
139+
contextStart = 0
140+
}
141+
contextEnd := iter.head + 50
142+
if contextEnd > len(iter.buf) {
143+
contextEnd = len(iter.buf)
144+
}
145+
context := string(iter.buf[contextStart:contextEnd])
146+
iter.Error = fmt.Errorf("%s: %s, error found in #%v byte of ...|%s|..., bigger context ...|%s|...",
147+
operation, msg, iter.head-peekStart, parsing, context)
148+
}
149+
150+
// CurrentBuffer gets current buffer as string for debugging purpose
151+
func (iter *Iterator) CurrentBuffer() string {
152+
peekStart := iter.head - 10
153+
if peekStart < 0 {
154+
peekStart = 0
155+
}
156+
return fmt.Sprintf("parsing #%v byte, around ...|%s|..., whole buffer ...|%s|...", iter.head,
157+
string(iter.buf[peekStart:iter.head]), string(iter.buf[0:len(iter.buf)]))
158+
}
159+
160+
func (iter *Iterator) readByte() (ret byte) {
161+
ret = iter.buf[iter.head]
162+
iter.head++
163+
return ret
164+
}
165+
166+
func (iter *Iterator) unreadByte() {
167+
if iter.Error != nil {
168+
return
169+
}
170+
iter.head--
171+
return
172+
}
173+
174+
func (iter *Iterator) nextToken() byte {
175+
// a variation of skip whitespaces, returning the next non-whitespace token
176+
for {
177+
for i := iter.head; i < len(iter.buf); i++ {
178+
c := iter.buf[i]
179+
switch c {
180+
case ' ', '\n', '\t', '\r':
181+
continue
182+
}
183+
iter.head = i + 1
184+
return c
185+
}
186+
return 0
187+
}
188+
}

iter_array.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package jsoniter
2+
3+
// ReadArray read array element, tells if the array has more element to read.
4+
func (iter *Iterator) ReadArray() (ret bool) {
5+
c := iter.nextToken()
6+
switch c {
7+
case 'n':
8+
iter.skipThreeBytes('u', 'l', 'l')
9+
return false // null
10+
case '[':
11+
c = iter.nextToken()
12+
if c != ']' {
13+
iter.unreadByte()
14+
return true
15+
}
16+
return false
17+
case ']':
18+
return false
19+
case ',':
20+
return true
21+
default:
22+
iter.ReportError("ReadArray", "expect [ or , or ] or n, but found "+string([]byte{c}))
23+
return
24+
}
25+
}

0 commit comments

Comments
 (0)