Support decoding floats, scientific notation for JSON [GH-5]

This commit is contained in:
Mitchell Hashimoto 2014-08-21 11:22:37 -07:00
parent b699557f16
commit e868ca02fd
7 changed files with 126 additions and 30 deletions

View File

@ -48,6 +48,8 @@ func (d *decoder) decode(name string, o *hcl.Object, result reflect.Value) error
switch k.Kind() {
case reflect.Bool:
return d.decodeBool(name, o, result)
case reflect.Float64:
return d.decodeFloat(name, o, result)
case reflect.Int:
return d.decodeInt(name, o, result)
case reflect.Interface:
@ -65,7 +67,7 @@ func (d *decoder) decode(name string, o *hcl.Object, result reflect.Value) error
return d.decodeStruct(name, o, result)
default:
return fmt.Errorf(
"%s: unknown kind to decode into: %s", name, result.Kind())
"%s: unknown kind to decode into: %s", name, k.Kind())
}
return nil
@ -82,6 +84,17 @@ func (d *decoder) decodeBool(name string, o *hcl.Object, result reflect.Value) e
return nil
}
func (d *decoder) decodeFloat(name string, o *hcl.Object, result reflect.Value) error {
switch o.Type {
case hcl.ValueTypeFloat:
result.Set(reflect.ValueOf(o.Value.(float64)))
default:
return fmt.Errorf("%s: unknown type %s", name, o.Type)
}
return nil
}
func (d *decoder) decodeInt(name string, o *hcl.Object, result reflect.Value) error {
switch o.Type {
case hcl.ValueTypeInt:
@ -142,6 +155,9 @@ func (d *decoder) decodeInterface(name string, o *hcl.Object, result reflect.Val
case hcl.ValueTypeBool:
var result bool
set = reflect.Indirect(reflect.New(reflect.TypeOf(result)))
case hcl.ValueTypeFloat:
var result float64
set = reflect.Indirect(reflect.New(reflect.TypeOf(result)))
case hcl.ValueTypeInt:
var result int
set = reflect.Indirect(reflect.New(reflect.TypeOf(result)))

View File

@ -33,6 +33,15 @@ func TestDecode_interface(t *testing.T) {
},
},
},
{
"scientific.json",
false,
map[string]interface{}{
"a": 1e-10,
"b": 1e+10,
"c": 1e10,
},
},
{
"terraform_heroku.hcl",
false,

View File

@ -43,6 +43,18 @@ func (x *jsonLex) Lex(yylval *jsonSymType) int {
}
switch c {
case 'e':
fallthrough
case 'E':
switch x.next() {
case '+':
return EPLUS
case '-':
return EMINUS
default:
x.backup()
return EPLUS
}
case '.':
return PERIOD
case '-':

View File

@ -22,12 +22,12 @@ import (
%type <num> int
%type <obj> number object pair value
%type <objlist> array elements members
%type <str> frac
%type <str> exp frac
%token <num> NUMBER
%token <str> COLON COMMA IDENTIFIER EQUAL NEWLINE STRING
%token <str> LEFTBRACE RIGHTBRACE LEFTBRACKET RIGHTBRACKET
%token <str> TRUE FALSE NULL MINUS PERIOD
%token <str> TRUE FALSE NULL MINUS PERIOD EPLUS EMINUS
%%
@ -153,6 +153,19 @@ number:
Value: f,
}
}
| int exp
{
fs := fmt.Sprintf("%d%s", $1, $2)
f, err := strconv.ParseFloat(fs, 64)
if err != nil {
panic(err)
}
$$ = &hcl.Object{
Type: hcl.ValueTypeFloat,
Value: f,
}
}
int:
MINUS int
@ -164,6 +177,16 @@ int:
$$ = $1
}
exp:
EPLUS NUMBER
{
$$ = "e" + strconv.FormatInt(int64($2), 10)
}
| EMINUS NUMBER
{
$$ = "e-" + strconv.FormatInt(int64($2), 10)
}
frac:
PERIOD NUMBER
{

View File

@ -36,6 +36,8 @@ const FALSE = 57358
const NULL = 57359
const MINUS = 57360
const PERIOD = 57361
const EPLUS = 57362
const EMINUS = 57363
var jsonToknames = []string{
"NUMBER",
@ -54,6 +56,8 @@ var jsonToknames = []string{
"NULL",
"MINUS",
"PERIOD",
"EPLUS",
"EMINUS",
}
var jsonStatenames = []string{}
@ -61,7 +65,7 @@ const jsonEofCode = 1
const jsonErrCode = 2
const jsonMaxDepth = 200
//line parse.y:173
//line parse.y:196
//line yacctab:1
var jsonExca = []int{
@ -70,59 +74,59 @@ var jsonExca = []int{
-2, 0,
}
const jsonNprod = 23
const jsonNprod = 26
const jsonPrivate = 57344
var jsonTokenNames []string
var jsonStates []string
const jsonLast = 45
const jsonLast = 50
var jsonAct = []int{
12, 23, 20, 25, 23, 3, 7, 13, 3, 10,
21, 26, 17, 18, 19, 22, 30, 23, 22, 7,
1, 5, 28, 13, 3, 29, 21, 32, 17, 18,
19, 22, 9, 33, 6, 31, 15, 2, 8, 24,
4, 27, 16, 14, 11,
12, 23, 26, 27, 28, 23, 3, 13, 3, 20,
21, 29, 17, 18, 19, 22, 7, 23, 5, 22,
7, 9, 31, 13, 3, 37, 21, 8, 17, 18,
19, 22, 32, 36, 6, 10, 35, 34, 38, 33,
15, 2, 1, 24, 11, 25, 4, 30, 16, 14,
}
var jsonPact = []int{
-6, -1000, -1000, 9, 26, -1000, -1000, 4, -1000, -4,
-5, -1000, -1000, 6, 15, -1000, -1000, 30, -1000, 10,
13, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-16, -3, 0, -1000, -1000, 12, -1000, 21, -1000, -1000,
-1000, -1000, 13, -1000,
-17, -3, 1, -1000, -1000, -1000, 35, 33, 32, -1000,
19, -1000, -1000, -1000, -1000, -1000, -1000, 13, -1000,
}
var jsonPgo = []int{
0, 2, 43, 36, 34, 0, 42, 41, 40, 39,
20,
0, 9, 49, 40, 34, 0, 48, 47, 46, 45,
43, 42,
}
var jsonR1 = []int{
0, 10, 3, 3, 8, 8, 4, 5, 5, 5,
0, 11, 3, 3, 8, 8, 4, 5, 5, 5,
5, 5, 5, 5, 6, 6, 7, 7, 2, 2,
1, 1, 9,
2, 1, 1, 9, 9, 10,
}
var jsonR2 = []int{
0, 1, 3, 2, 1, 3, 3, 1, 1, 1,
1, 1, 1, 1, 2, 3, 1, 3, 1, 2,
2, 1, 2,
2, 2, 1, 2, 2, 2,
}
var jsonChk = []int{
-1000, -10, -3, 11, -8, 12, -4, 10, 12, 6,
-1000, -11, -3, 11, -8, 12, -4, 10, 12, 6,
5, -4, -5, 10, -2, -3, -6, 15, 16, 17,
-1, 13, 18, 4, -9, 19, 14, -7, -5, -1,
4, 14, 6, -5,
-1, 13, 18, 4, -10, -9, 19, 20, 21, 14,
-7, -5, -1, 4, 4, 4, 14, 6, -5,
}
var jsonDef = []int{
0, -2, 1, 0, 0, 3, 4, 0, 2, 0,
0, 5, 6, 7, 8, 9, 10, 11, 12, 13,
18, 0, 0, 21, 19, 0, 14, 0, 16, 20,
22, 15, 0, 17,
18, 0, 0, 22, 19, 20, 0, 0, 0, 14,
0, 16, 21, 25, 23, 24, 15, 0, 17,
}
var jsonTok1 = []int{
@ -131,7 +135,7 @@ var jsonTok1 = []int{
var jsonTok2 = []int{
2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
}
var jsonTok3 = []int{
0,
@ -489,17 +493,41 @@ jsondefault:
}
}
case 20:
//line parse.y:159
//line parse.y:157
{
fs := fmt.Sprintf("%d%s", jsonS[jsonpt-1].num, jsonS[jsonpt-0].str)
f, err := strconv.ParseFloat(fs, 64)
if err != nil {
panic(err)
}
jsonVAL.obj = &hcl.Object{
Type: hcl.ValueTypeFloat,
Value: f,
}
}
case 21:
//line parse.y:172
{
jsonVAL.num = jsonS[jsonpt-0].num * -1
}
case 21:
//line parse.y:163
case 22:
//line parse.y:176
{
jsonVAL.num = jsonS[jsonpt-0].num
}
case 22:
//line parse.y:169
case 23:
//line parse.y:182
{
jsonVAL.str = "e" + strconv.FormatInt(int64(jsonS[jsonpt-0].num), 10)
}
case 24:
//line parse.y:186
{
jsonVAL.str = "e-" + strconv.FormatInt(int64(jsonS[jsonpt-0].num), 10)
}
case 25:
//line parse.y:192
{
jsonVAL.str = strconv.FormatInt(int64(jsonS[jsonpt-0].num), 10)
}

View File

@ -0,0 +1,3 @@
a = 1e-10
b = 1e+10
c = 1e10

View File

@ -0,0 +1,5 @@
{
"a": 1e-10,
"b": 1e+10,
"c": 1e10
}