Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #4 from opethe1st/support-numbers
Support numbers
  • Loading branch information
opethe1st committed Aug 26, 2019
2 parents 70f0005 + a3d4b93 commit 2be3870
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 13 deletions.
78 changes: 74 additions & 4 deletions load.go
Expand Up @@ -9,6 +9,8 @@ package json

import (
"fmt"
"math"
"strconv"
"unicode"
)

Expand All @@ -21,14 +23,14 @@ func Load(s string) interface{} {
func load(iter *iterator) interface{} {
consumeWhiteSpace(iter)
switch {
case iter.isEnd():
return nil
case iter.getCurrent() == 'n':
return loadKeyword(iter, "null", nil)
case iter.getCurrent() == 't':
return loadKeyword(iter, "true", true)
case iter.getCurrent() == 'f':
return loadKeyword(iter, "false", false)
case isNumber(iter):
return loadNumber(iter)
case iter.getCurrent() == '"':
return loadString(iter)
case iter.getCurrent() == '[':
Expand All @@ -54,7 +56,74 @@ func loadKeyword(iter *iterator, keyword string, value interface{}) interface{}
return value
}

func loadString(iter *iterator) interface{} {
func isNumber(iter *iterator) bool {
switch iter.getCurrent() {
case '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '0':
return true
}
return false
}

func loadNumber(iter *iterator) interface{} {
//negative numbers
sign := 1.0
if iter.getCurrent() == '-' {
sign = -1.0
iter.advance()
}
num := 0.0
for !iter.isEnd() && unicode.IsDigit(rune(iter.getCurrent())) {
num *= 10
val, _ := strconv.ParseInt(string(iter.getCurrent()), 10, 64)
num += float64(val)
iter.advance()
}

// decimal
// some of the code here is a duplicate of what is above, I should consolidate into one function.
consume(iter, '.')
frac := 0.0
power := 0.1
for !iter.isEnd() && unicode.IsDigit(rune(iter.getCurrent())) {
val, _ := strconv.ParseInt(string(iter.getCurrent()), 10, 64)
frac += power * float64(val)
power *= 0.1
iter.advance()
}

exponent := 0.0
//exponent
if !iter.isEnd() && ((iter.getCurrent() == 'e') || (iter.getCurrent() == 'E')) {
if iter.getCurrent() == 'e' {
consume(iter, 'e')
}
if iter.getCurrent() == 'E' {
consume(iter, 'E')
}
exponentSign := 1.0
//TODO(ope) this is subtly wrong since it allows +-123234, I will fix later
if !iter.isEnd() && iter.getCurrent() == '+' {
consume(iter, '+')
}
if !iter.isEnd() && iter.getCurrent() == '-' {
consume(iter, '-')
exponentSign = -1.0
}
// there needs to be at least one digit after an exponent
exponent = 0.0
for !iter.isEnd() && unicode.IsDigit(rune(iter.getCurrent())) {
exponent *= 10
val, _ := strconv.ParseInt(string(iter.getCurrent()), 10, 64)
exponent += float64(val)
iter.advance()
}
exponent *= exponentSign
}
fmt.Println(num, frac, exponent)
return (num + frac) * sign * math.Pow(10, exponent)
}

func loadString(iter *iterator) string {
consume(iter, '"')
s := make([]rune, 0)
mapping := map[rune]rune{
Expand Down Expand Up @@ -101,6 +170,7 @@ func loadString(iter *iterator) interface{} {
//need to handle the default case and handle u and hex digits
case 'u':
var ans rune
// I should make sure these are valid hex digits btw, but will leave it for error reporting
for i := 0; i < 4; i++ {
iter.advance() // move past the 'u'
fmt.Println(i, ans, string(iter.getCurrent()))
Expand Down Expand Up @@ -170,7 +240,7 @@ func consumeWhiteSpace(iter *iterator) {

func consume(iter *iterator, char byte) {
// actually should probably raise an error if char isn't consumed
if iter.getCurrent() == char {
if !iter.isEnd() && iter.getCurrent() == char {
iter.advance()
}
}
36 changes: 27 additions & 9 deletions load_test.go
@@ -1,6 +1,7 @@
package json

import (
"math"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -29,6 +30,7 @@ func TestLoad(t *testing.T) {
"k5": true,
"k6": false,
"k 6": null,
"k7": 123456
}`, map[string]interface{}{
"k1": "v1",
"k2": []interface{}{"v2"},
Expand All @@ -40,6 +42,7 @@ func TestLoad(t *testing.T) {
"k5": true,
"k6": false,
"k\t6": nil,
"k7": 123456.0,
},
},
}
Expand Down Expand Up @@ -70,6 +73,7 @@ func TestLoadKeyword(t *testing.T) {
}

func TestLoadString(t *testing.T) {
assert := assert.New(t) // redefinition here -- ugly!
testCases := []TestCase{
{`"Key"`, "Key"},
{`" Key"`, " Key"},
Expand All @@ -84,25 +88,39 @@ func TestLoadString(t *testing.T) {
}
for _, testcase := range testCases {
iter := &iterator{s: testcase.input}
if output := loadString(iter); output != testcase.expectedOutput {
t.Errorf("Expected loadString(%v) to be %v but got %v", iter, testcase.expectedOutput, output)
}
output := loadString(iter)
assert.Equal(testcase.expectedOutput, output, "Expected loadNumber(%v) to be %v but got %v", iter, testcase.expectedOutput, output)

}

testCases = []TestCase{
{`"Key"`, 5},
{`" Key"`, 8},
{`"Key" `, 5},
}

func TestLoadNumber(t *testing.T) {
testCases := []TestCase{
{`123`, 123.0},
{`-123`, -123.0},
{`-123.123`, -123.123},
{`0.234`, 0.234},
{`1.234e2`, 123.4},
{`-1.234e2`, -123.4},
{`-0.234e2`, -23.4},
}
for _, testcase := range testCases {
iter := &iterator{s: testcase.input}
if loadString(iter); iter.offset != testcase.expectedOutput {
t.Errorf("Expected loadString(%v) to be %v but got %v", iter, testcase.expectedOutput, iter.offset)
output := loadNumber(iter)
if !floatEquals(output.(float64), testcase.expectedOutput.(float64)) {
t.Errorf("Expected loadNumber(%v) to be %v but got %v", iter, testcase.expectedOutput, output)
}
}
}

func floatEquals(a, b float64) bool {
if math.Abs(a-b) < 0.00000001 {
return true
}
return false
}

func TestLoadSequence(t *testing.T) {
assert := assert.New(t)
testCases := []TestCase{
Expand Down

0 comments on commit 2be3870

Please sign in to comment.