Ensure Parse handles NaN/Inf and returns correct Index

This commit is contained in:
tidwall 2021-10-28 09:09:00 -07:00
parent 0b52f9a361
commit 7cadbb5756
2 changed files with 73 additions and 24 deletions

View File

@ -426,7 +426,8 @@ end:
// use the Valid function first.
func Parse(json string) Result {
var value Result
for i := 0; i < len(json); i++ {
i := 0
for ; i < len(json); i++ {
if json[i] == '{' || json[i] == '[' {
value.Type = JSON
value.Raw = json[i:] // just take the entire raw
@ -436,16 +437,20 @@ func Parse(json string) Result {
continue
}
switch json[i] {
default:
if (json[i] >= '0' && json[i] <= '9') || json[i] == '-' {
case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'i', 'I', 'N':
value.Type = Number
value.Raw, value.Num = tonum(json[i:])
case 'n':
if i+1 < len(json) && json[i+1] != 'u' {
// nan
value.Type = Number
value.Raw, value.Num = tonum(json[i:])
} else {
return Result{}
// null
value.Type = Null
value.Raw = tolit(json[i:])
}
case 'n':
value.Type = Null
value.Raw = tolit(json[i:])
case 't':
value.Type = True
value.Raw = tolit(json[i:])
@ -455,9 +460,14 @@ func Parse(json string) Result {
case '"':
value.Type = String
value.Raw, value.Str = tostr(json[i:])
default:
return Result{}
}
break
}
if value.Exists() {
value.Index = i
}
return value
}
@ -531,20 +541,12 @@ func tonum(json string) (raw string, num float64) {
return
}
// could be a '+' or '-'. let's assume so.
continue
} else if json[i] == ']' || json[i] == '}' {
// break on ']' or '}'
raw = json[:i]
num, _ = strconv.ParseFloat(raw, 64)
return
}
if json[i] < ']' {
// probably a valid number
continue
}
if json[i] == 'e' || json[i] == 'E' {
// allow for exponential numbers
continue
}
// likely a ']' or '}'
raw = json[:i]
num, _ = strconv.ParseFloat(raw, 64)
return
}
raw = json
num, _ = strconv.ParseFloat(raw, 64)
@ -2971,3 +2973,31 @@ func stringBytes(s string) []byte {
func bytesString(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
func GetPath(r Result, json string) (string, bool) {
if len(r.Raw) == 0 || len(json) == 0 {
return "", false
}
p := uintptr((*(*stringHeader)(unsafe.Pointer(&(r.Raw)))).data)
s := uintptr((*(*stringHeader)(unsafe.Pointer(&(json)))).data)
e := s + uintptr(len(json))
if p < s || p >= e {
return "", false
}
i := int(p - s)
_ = i
// for ; i >= 0; i-- {
// if json[i] <= ' ' {
// } else if json[i] == ':' {
// // inside of an object, read the key string
// } else if json[i] == ',' {
// // array-value
// } else if json[i] == '[' {
// // array-value (end or array)
// } else {
// }
// }
// return "", false
return "", false
}

View File

@ -717,10 +717,6 @@ var exampleJSON = `{
}
}`
func TestNewParse(t *testing.T) {
//fmt.Printf("%v\n", parse2(exampleJSON, "widget").String())
}
func TestUnmarshalMap(t *testing.T) {
var m1 = Parse(exampleJSON).Value().(map[string]interface{})
var m2 map[string]interface{}
@ -2250,16 +2246,28 @@ func TestNaNInf(t *testing.T) {
r := Get(json, fmt.Sprintf("%d", i))
assert(t, r.Raw == raws[i])
assert(t, r.Num == nums[i] || (math.IsNaN(r.Num) && math.IsNaN(nums[i])))
assert(t, r.Type == Number)
}
var i int
Parse(json).ForEach(func(_, r Result) bool {
assert(t, r.Raw == raws[i])
assert(t, r.Num == nums[i] || (math.IsNaN(r.Num) && math.IsNaN(nums[i])))
assert(t, r.Type == Number)
i++
return true
})
// Parse should also return valid numbers
assert(t, math.IsNaN(Parse("nan").Float()))
assert(t, math.IsNaN(Parse("NaN").Float()))
assert(t, math.IsNaN(Parse(" NaN").Float()))
assert(t, math.IsInf(Parse("+inf").Float(), +1))
assert(t, math.IsInf(Parse("-inf").Float(), -1))
assert(t, math.IsInf(Parse("+INF").Float(), +1))
assert(t, math.IsInf(Parse("-INF").Float(), -1))
assert(t, math.IsInf(Parse(" +INF").Float(), +1))
assert(t, math.IsInf(Parse(" -INF").Float(), -1))
}
func TestEmptyValueQuery(t *testing.T) {
@ -2273,3 +2281,14 @@ func TestEmptyValueQuery(t *testing.T) {
`#(!=)#`).Raw ==
`["ig","tw","fb","tw","ig","tw"]`)
}
func TestParseIndex(t *testing.T) {
assert(t, Parse(`{}`).Index == 0)
assert(t, Parse(` {}`).Index == 1)
assert(t, Parse(` []`).Index == 1)
assert(t, Parse(` true`).Index == 1)
assert(t, Parse(` false`).Index == 1)
assert(t, Parse(` null`).Index == 1)
assert(t, Parse(` +inf`).Index == 1)
assert(t, Parse(` -inf`).Index == 1)
}