Skip to content

Commit

Permalink
8 add tests for RFC 7159 (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
spyzhov authored Apr 24, 2020
1 parent 787d083 commit 2463e6f
Show file tree
Hide file tree
Showing 16 changed files with 2,995 additions and 158 deletions.
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,11 @@ $ go test -bench=. -cpu=1 -benchmem
goos: linux
goarch: amd64
pkg: github.com/spyzhov/ajson
BenchmarkUnmarshal_AJSON 87807 13668 ns/op 5344 B/op 95 allocs/op
BenchmarkUnmarshal_JSON 64012 17560 ns/op 968 B/op 31 allocs/op
BenchmarkJSONPath_all_prices 56743 26049 ns/op 7368 B/op 161 allocs/op
BenchmarkUnmarshal_AJSON 91104 13756 ns/op 5344 B/op 95 allocs/op
BenchmarkUnmarshal_JSON 67794 16851 ns/op 968 B/op 31 allocs/op
BenchmarkJSONPath_all_prices 49650 25073 ns/op 7368 B/op 161 allocs/op
```

# License

MIT licensed. See the [LICENSE](LICENSE) file for details.
139 changes: 73 additions & 66 deletions buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@ const (
question byte = '?'
)

type rpn []string
type tokens []string
type (
rpn []string
tokens []string
)

var (
_null = []byte("null")
Expand Down Expand Up @@ -115,67 +117,80 @@ func (b *buffer) skipAny(s map[byte]bool) error {
return io.EOF
}

func (b *buffer) numeric() error {
var c byte
const (
_none = 0 // 0
_sign = 1 << 0 // 1
_dot = 1 << 1 // 2
_num = 1 << 2 // 4
_exp = 1 << 3 // 8
// if token is true - skip error from stateTransitionTable, just stop on unknown state
func (b *buffer) numeric(token bool) error {
var (
last = GO
state states
class classes
)
find := 0
for ; b.index < b.length; b.index++ {
c = b.data[b.index]
switch true {
case c >= '0' && c <= '9':
find |= _num
case c == '.':
if find&_exp != 0 { // exp part of numeric MUST contains only digits
return errorSymbol(b)
}
if find&_dot == 0 {
find |= _dot
} else {
return errorSymbol(b)
}
case c == '+' || c == '-':
if find == _none || find == _exp {
find |= _sign
} else {
if find&_num == 0 {
return errorSymbol(b)
}
return nil
}
case c == 'e' || c == 'E':
if find&_exp == 0 && find&_num != 0 { // exp without base part
find = _exp
} else {
return errorSymbol(b)
}
default:
if find&_num != 0 {
return nil
class = b.getClasses()
if class == __ {
return b.errorSymbol()
}
state = stateTransitionTable[last][class]
if state == __ {
if token {
break
}
return errorSymbol(b)
return b.errorSymbol()
}
if state < __ {
return nil
}
if state < MI || state > E3 {
return nil
}
last = state
}
if find&_num != 0 {
return io.EOF
if last != ZE && last != IN && last != FR && last != E3 {
return b.errorSymbol()
}
return errorEOF(b)
return nil
}

func (b *buffer) string(search byte) error {
err := b.step()
if err != nil {
return errorEOF(b)
func (b *buffer) getClasses() classes {
return b.classes(asciiClasses)
}

func (b *buffer) getQuoteClasses() classes {
return b.classes(quoteAsciiClasses)
}

func (b *buffer) classes(source [128]classes) classes {
if b.data[b.index] >= 128 {
return C_ETC
}
if b.skip(search) != nil {
return errorEOF(b)
return source[b.data[b.index]]
}

func (b *buffer) string(search byte) error {
var (
last = GO
state states
class classes
)
for ; b.index < b.length; b.index++ {
if search == quote {
class = b.getQuoteClasses()
} else {
class = b.getClasses()
}

if class == __ {
return b.errorSymbol()
}
state = stateTransitionTable[last][class]
if state == __ {
return b.errorSymbol()
}
if state < __ {
return nil
}
last = state
}
return nil
return b.errorSymbol()
}

func (b *buffer) null() error {
Expand All @@ -196,7 +211,8 @@ func (b *buffer) word(word []byte) error {
index := 0
for ; b.index < b.length; b.index++ {
c = b.data[b.index]
if c != word[index] && c != (word[index]-32) {
// if c != word[index] && c != (word[index]-32) {
if c != word[index] {
return errorSymbol(b)
}
index++
Expand Down Expand Up @@ -281,7 +297,7 @@ tokenLoop:
if !find {
find = true
start = b.index
err = b.numeric()
err = b.numeric(true)
if err == nil || err == io.EOF {
b.index--
continue
Expand Down Expand Up @@ -369,7 +385,7 @@ func (b *buffer) rpn() (result rpn, err error) {
case (c >= '0' && c <= '9') || c == '.': // numbers
variable = true
start = b.index
err = b.numeric()
err = b.numeric(true)
if err != nil && err != io.EOF {
return nil, err
}
Expand Down Expand Up @@ -515,7 +531,7 @@ func (b *buffer) tokenize() (result tokens, err error) {
case (c >= '0' && c <= '9') || c == dot: // numbers
variable = true
start = b.index
err = b.numeric()
err = b.numeric(true)
if err != nil && err != io.EOF {
if c == dot {
err = nil
Expand Down Expand Up @@ -651,15 +667,6 @@ func _bools(left, right *Node) (lnum, rnum bool, err error) {
return
}

func _nulls(left, right *Node) (lnum, rnum interface{}, err error) {
lnum, err = left.GetNull()
if err != nil {
return
}
rnum, err = right.GetNull()
return
}

func _strings(left, right *Node) (lnum, rnum string, err error) {
lnum, err = left.GetString()
if err != nil {
Expand Down
7 changes: 3 additions & 4 deletions buffer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,8 @@ func TestBuffer_Numeric(t *testing.T) {
{value: "..3", index: 0, fail: true},
{value: "e.", index: 0, fail: true},
{value: ".e.", index: 0, fail: true},
{value: "1.e1", index: 4, fail: false},
{value: "0.e0", index: 4, fail: false},
{value: "0.e0", index: 4, fail: false},
{value: "1.e1", index: 0, fail: true},
{value: "0.e0", index: 0, fail: true},
{value: "0+0", index: 1, fail: false},
{value: "0-1", index: 1, fail: false},
{value: "++1", index: 0, fail: true},
Expand All @@ -228,7 +227,7 @@ func TestBuffer_Numeric(t *testing.T) {
for _, test := range tests {
t.Run(test.value, func(t *testing.T) {
buf := newBuffer([]byte(test.value))
err := buf.numeric()
err := buf.numeric(true)
if !test.fail && err != nil && err != io.EOF {
t.Errorf("Unexpected error: %s", err.Error())
} else if test.fail && (err == nil || err == io.EOF) {
Expand Down
53 changes: 31 additions & 22 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,36 +79,42 @@ func Unmarshal(data []byte) (root *Node, err error) {
current = previous(current)
case b == quotes:
// Detected: String OR Key
if current != nil && current.IsObject() && key == nil { // Detected: Key
key, err = getString(buf)
if err == nil {
err = buf.step()
}
found = false
} else { // Detected: String
current, err = newNode(current, buf, String, &key)
if err != nil {
if current != nil && current.IsObject() {
if key == nil { // Detected: Key
key, err = getString(buf)
if err == nil {
err = buf.step()
}
found = false

break
} else if last != colon {
return nil, errorSymbol(buf)
}
err = buf.string(quotes)
current.borders[1] = buf.index + 1
if err == nil {
err = buf.step()
}
found = true
current = previous(current)
}
// Detected: String
current, err = newNode(current, buf, String, &key)
if err != nil {
break
}
err = buf.string(quotes)
current.borders[1] = buf.index + 1
if err == nil {
err = buf.step()
}
found = true
current = previous(current)
case (b >= '0' && b <= '9') || b == '.' || b == '+' || b == '-':
// Detected: Numeric
current, err = newNode(current, buf, Numeric, &key)
if err != nil {
break
}
err = buf.numeric()
err = buf.numeric(false)
current.borders[1] = buf.index
found = true
current = previous(current)
case b == 'n' || b == 'N':
case b == 'n':
// Detected: Null
current, err = newNode(current, buf, Null, &key)
if err != nil {
Expand All @@ -121,13 +127,13 @@ func Unmarshal(data []byte) (root *Node, err error) {
}
found = true
current = previous(current)
case b == 't' || b == 'T' || b == 'f' || b == 'F':
case b == 't' || b == 'f':
// Detected: Bool
current, err = newNode(current, buf, Bool, &key)
if err != nil {
break
}
if b == 't' || b == 'T' {
if b == 't' {
err = buf.true()
} else {
err = buf.false()
Expand Down Expand Up @@ -161,7 +167,7 @@ func Unmarshal(data []byte) (root *Node, err error) {

// outer
if err == io.EOF {
if current == nil || current.parent != nil || !current.ready() {
if current == nil || current.parent != nil || !current.ready() || !found {
return nil, errorEOF(buf)
}
err = nil
Expand Down Expand Up @@ -213,6 +219,9 @@ func getString(b *buffer) (*string, error) {
if err != nil {
return nil, err
}
value := string(b.data[start+1 : b.index])
value, ok := unquote(b.data[start : b.index+1])
if !ok {
return nil, errorSymbol(b)
}
return &value, nil
}
Loading

0 comments on commit 2463e6f

Please sign in to comment.