Skip to content

Commit 2be3870

Browse files
authored
Merge pull request #4 from opethe1st/support-numbers
Support numbers
2 parents 70f0005 + a3d4b93 commit 2be3870

2 files changed

Lines changed: 101 additions & 13 deletions

File tree

load.go

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ package json
99

1010
import (
1111
"fmt"
12+
"math"
13+
"strconv"
1214
"unicode"
1315
)
1416

@@ -21,14 +23,14 @@ func Load(s string) interface{} {
2123
func load(iter *iterator) interface{} {
2224
consumeWhiteSpace(iter)
2325
switch {
24-
case iter.isEnd():
25-
return nil
2626
case iter.getCurrent() == 'n':
2727
return loadKeyword(iter, "null", nil)
2828
case iter.getCurrent() == 't':
2929
return loadKeyword(iter, "true", true)
3030
case iter.getCurrent() == 'f':
3131
return loadKeyword(iter, "false", false)
32+
case isNumber(iter):
33+
return loadNumber(iter)
3234
case iter.getCurrent() == '"':
3335
return loadString(iter)
3436
case iter.getCurrent() == '[':
@@ -54,7 +56,74 @@ func loadKeyword(iter *iterator, keyword string, value interface{}) interface{}
5456
return value
5557
}
5658

57-
func loadString(iter *iterator) interface{} {
59+
func isNumber(iter *iterator) bool {
60+
switch iter.getCurrent() {
61+
case '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '0':
62+
return true
63+
}
64+
return false
65+
}
66+
67+
func loadNumber(iter *iterator) interface{} {
68+
//negative numbers
69+
sign := 1.0
70+
if iter.getCurrent() == '-' {
71+
sign = -1.0
72+
iter.advance()
73+
}
74+
num := 0.0
75+
for !iter.isEnd() && unicode.IsDigit(rune(iter.getCurrent())) {
76+
num *= 10
77+
val, _ := strconv.ParseInt(string(iter.getCurrent()), 10, 64)
78+
num += float64(val)
79+
iter.advance()
80+
}
81+
82+
// decimal
83+
// some of the code here is a duplicate of what is above, I should consolidate into one function.
84+
consume(iter, '.')
85+
frac := 0.0
86+
power := 0.1
87+
for !iter.isEnd() && unicode.IsDigit(rune(iter.getCurrent())) {
88+
val, _ := strconv.ParseInt(string(iter.getCurrent()), 10, 64)
89+
frac += power * float64(val)
90+
power *= 0.1
91+
iter.advance()
92+
}
93+
94+
exponent := 0.0
95+
//exponent
96+
if !iter.isEnd() && ((iter.getCurrent() == 'e') || (iter.getCurrent() == 'E')) {
97+
if iter.getCurrent() == 'e' {
98+
consume(iter, 'e')
99+
}
100+
if iter.getCurrent() == 'E' {
101+
consume(iter, 'E')
102+
}
103+
exponentSign := 1.0
104+
//TODO(ope) this is subtly wrong since it allows +-123234, I will fix later
105+
if !iter.isEnd() && iter.getCurrent() == '+' {
106+
consume(iter, '+')
107+
}
108+
if !iter.isEnd() && iter.getCurrent() == '-' {
109+
consume(iter, '-')
110+
exponentSign = -1.0
111+
}
112+
// there needs to be at least one digit after an exponent
113+
exponent = 0.0
114+
for !iter.isEnd() && unicode.IsDigit(rune(iter.getCurrent())) {
115+
exponent *= 10
116+
val, _ := strconv.ParseInt(string(iter.getCurrent()), 10, 64)
117+
exponent += float64(val)
118+
iter.advance()
119+
}
120+
exponent *= exponentSign
121+
}
122+
fmt.Println(num, frac, exponent)
123+
return (num + frac) * sign * math.Pow(10, exponent)
124+
}
125+
126+
func loadString(iter *iterator) string {
58127
consume(iter, '"')
59128
s := make([]rune, 0)
60129
mapping := map[rune]rune{
@@ -101,6 +170,7 @@ func loadString(iter *iterator) interface{} {
101170
//need to handle the default case and handle u and hex digits
102171
case 'u':
103172
var ans rune
173+
// I should make sure these are valid hex digits btw, but will leave it for error reporting
104174
for i := 0; i < 4; i++ {
105175
iter.advance() // move past the 'u'
106176
fmt.Println(i, ans, string(iter.getCurrent()))
@@ -170,7 +240,7 @@ func consumeWhiteSpace(iter *iterator) {
170240

171241
func consume(iter *iterator, char byte) {
172242
// actually should probably raise an error if char isn't consumed
173-
if iter.getCurrent() == char {
243+
if !iter.isEnd() && iter.getCurrent() == char {
174244
iter.advance()
175245
}
176246
}

load_test.go

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package json
22

33
import (
4+
"math"
45
"testing"
56

67
"github.com/stretchr/testify/assert"
@@ -29,6 +30,7 @@ func TestLoad(t *testing.T) {
2930
"k5": true,
3031
"k6": false,
3132
"k 6": null,
33+
"k7": 123456
3234
}`, map[string]interface{}{
3335
"k1": "v1",
3436
"k2": []interface{}{"v2"},
@@ -40,6 +42,7 @@ func TestLoad(t *testing.T) {
4042
"k5": true,
4143
"k6": false,
4244
"k\t6": nil,
45+
"k7": 123456.0,
4346
},
4447
},
4548
}
@@ -70,6 +73,7 @@ func TestLoadKeyword(t *testing.T) {
7073
}
7174

7275
func TestLoadString(t *testing.T) {
76+
assert := assert.New(t) // redefinition here -- ugly!
7377
testCases := []TestCase{
7478
{`"Key"`, "Key"},
7579
{`" Key"`, " Key"},
@@ -84,25 +88,39 @@ func TestLoadString(t *testing.T) {
8488
}
8589
for _, testcase := range testCases {
8690
iter := &iterator{s: testcase.input}
87-
if output := loadString(iter); output != testcase.expectedOutput {
88-
t.Errorf("Expected loadString(%v) to be %v but got %v", iter, testcase.expectedOutput, output)
89-
}
91+
output := loadString(iter)
92+
assert.Equal(testcase.expectedOutput, output, "Expected loadNumber(%v) to be %v but got %v", iter, testcase.expectedOutput, output)
9093

9194
}
9295

93-
testCases = []TestCase{
94-
{`"Key"`, 5},
95-
{`" Key"`, 8},
96-
{`"Key" `, 5},
96+
}
97+
98+
func TestLoadNumber(t *testing.T) {
99+
testCases := []TestCase{
100+
{`123`, 123.0},
101+
{`-123`, -123.0},
102+
{`-123.123`, -123.123},
103+
{`0.234`, 0.234},
104+
{`1.234e2`, 123.4},
105+
{`-1.234e2`, -123.4},
106+
{`-0.234e2`, -23.4},
97107
}
98108
for _, testcase := range testCases {
99109
iter := &iterator{s: testcase.input}
100-
if loadString(iter); iter.offset != testcase.expectedOutput {
101-
t.Errorf("Expected loadString(%v) to be %v but got %v", iter, testcase.expectedOutput, iter.offset)
110+
output := loadNumber(iter)
111+
if !floatEquals(output.(float64), testcase.expectedOutput.(float64)) {
112+
t.Errorf("Expected loadNumber(%v) to be %v but got %v", iter, testcase.expectedOutput, output)
102113
}
103114
}
104115
}
105116

117+
func floatEquals(a, b float64) bool {
118+
if math.Abs(a-b) < 0.00000001 {
119+
return true
120+
}
121+
return false
122+
}
123+
106124
func TestLoadSequence(t *testing.T) {
107125
assert := assert.New(t)
108126
testCases := []TestCase{

0 commit comments

Comments
 (0)