json: Basic parsing of number values

This commit is contained in:
Martin Atkins 2017-05-17 07:34:33 -07:00
parent 4100bdfd2f
commit b073937523
2 changed files with 121 additions and 1 deletions

View File

@ -3,6 +3,7 @@ package json
import (
"encoding/json"
"fmt"
"math/big"
"github.com/apparentlymart/go-zcl/zcl"
)
@ -207,7 +208,41 @@ func parseArray(p *peeker) (node, zcl.Diagnostics) {
}
func parseNumber(p *peeker) (node, zcl.Diagnostics) {
return nil, nil
tok := p.Read()
// Use encoding/json to validate the number syntax.
// TODO: Do this more directly to produce better diagnostics.
var num json.Number
err := json.Unmarshal(tok.Bytes, &num)
if err != nil {
return nil, zcl.Diagnostics{
{
Severity: zcl.DiagError,
Summary: "Invalid JSON number",
Detail: fmt.Sprintf("There is a syntax error in the given JSON number."),
Subject: &tok.Range,
},
}
}
f, _, err := (&big.Float{}).Parse(string(num), 10)
if err != nil {
// Should never happen if above passed, since JSON numbers are a subset
// of what big.Float can parse...
return nil, zcl.Diagnostics{
{
Severity: zcl.DiagError,
Summary: "Invalid JSON number",
Detail: fmt.Sprintf("There is a syntax error in the given JSON number."),
Subject: &tok.Range,
},
}
}
return &numberVal{
Value: f,
SrcRange: tok.Range,
}, nil
}
func parseString(p *peeker) (node, zcl.Diagnostics) {

View File

@ -1,6 +1,7 @@
package json
import (
"math/big"
"reflect"
"testing"
@ -111,6 +112,82 @@ func TestParse(t *testing.T) {
nil,
1,
},
{
`1`,
&numberVal{
Value: mustBigFloat("1"),
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
End: zcl.Pos{Line: 1, Column: 2, Byte: 1},
},
},
0,
},
{
`1.2`,
&numberVal{
Value: mustBigFloat("1.2"),
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
End: zcl.Pos{Line: 1, Column: 4, Byte: 3},
},
},
0,
},
{
`-1`,
&numberVal{
Value: mustBigFloat("-1"),
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
End: zcl.Pos{Line: 1, Column: 3, Byte: 2},
},
},
0,
},
{
`1.2e5`,
&numberVal{
Value: mustBigFloat("120000"),
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
End: zcl.Pos{Line: 1, Column: 6, Byte: 5},
},
},
0,
},
{
`1.2e+5`,
&numberVal{
Value: mustBigFloat("120000"),
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
End: zcl.Pos{Line: 1, Column: 7, Byte: 6},
},
},
0,
},
{
`1.2e-5`,
&numberVal{
Value: mustBigFloat("1.2e-5"),
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
End: zcl.Pos{Line: 1, Column: 7, Byte: 6},
},
},
0,
},
{
`.1`,
nil,
1,
},
{
`+2`,
nil,
1,
},
// Objects
{
@ -259,3 +336,11 @@ func TestParse(t *testing.T) {
})
}
}
func mustBigFloat(s string) *big.Float {
f, _, err := (&big.Float{}).Parse(s, 10)
if err != nil {
panic(err)
}
return f
}