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() { switch k.Kind() {
case reflect.Bool: case reflect.Bool:
return d.decodeBool(name, o, result) return d.decodeBool(name, o, result)
case reflect.Float64:
return d.decodeFloat(name, o, result)
case reflect.Int: case reflect.Int:
return d.decodeInt(name, o, result) return d.decodeInt(name, o, result)
case reflect.Interface: 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) return d.decodeStruct(name, o, result)
default: default:
return fmt.Errorf( 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 return nil
@ -82,6 +84,17 @@ func (d *decoder) decodeBool(name string, o *hcl.Object, result reflect.Value) e
return nil 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 { func (d *decoder) decodeInt(name string, o *hcl.Object, result reflect.Value) error {
switch o.Type { switch o.Type {
case hcl.ValueTypeInt: case hcl.ValueTypeInt:
@ -142,6 +155,9 @@ func (d *decoder) decodeInterface(name string, o *hcl.Object, result reflect.Val
case hcl.ValueTypeBool: case hcl.ValueTypeBool:
var result bool var result bool
set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) 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: case hcl.ValueTypeInt:
var result int var result int
set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) 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", "terraform_heroku.hcl",
false, false,

View File

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

View File

@ -22,12 +22,12 @@ import (
%type <num> int %type <num> int
%type <obj> number object pair value %type <obj> number object pair value
%type <objlist> array elements members %type <objlist> array elements members
%type <str> frac %type <str> exp frac
%token <num> NUMBER %token <num> NUMBER
%token <str> COLON COMMA IDENTIFIER EQUAL NEWLINE STRING %token <str> COLON COMMA IDENTIFIER EQUAL NEWLINE STRING
%token <str> LEFTBRACE RIGHTBRACE LEFTBRACKET RIGHTBRACKET %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, 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: int:
MINUS int MINUS int
@ -164,6 +177,16 @@ int:
$$ = $1 $$ = $1
} }
exp:
EPLUS NUMBER
{
$$ = "e" + strconv.FormatInt(int64($2), 10)
}
| EMINUS NUMBER
{
$$ = "e-" + strconv.FormatInt(int64($2), 10)
}
frac: frac:
PERIOD NUMBER PERIOD NUMBER
{ {

View File

@ -36,6 +36,8 @@ const FALSE = 57358
const NULL = 57359 const NULL = 57359
const MINUS = 57360 const MINUS = 57360
const PERIOD = 57361 const PERIOD = 57361
const EPLUS = 57362
const EMINUS = 57363
var jsonToknames = []string{ var jsonToknames = []string{
"NUMBER", "NUMBER",
@ -54,6 +56,8 @@ var jsonToknames = []string{
"NULL", "NULL",
"MINUS", "MINUS",
"PERIOD", "PERIOD",
"EPLUS",
"EMINUS",
} }
var jsonStatenames = []string{} var jsonStatenames = []string{}
@ -61,7 +65,7 @@ const jsonEofCode = 1
const jsonErrCode = 2 const jsonErrCode = 2
const jsonMaxDepth = 200 const jsonMaxDepth = 200
//line parse.y:173 //line parse.y:196
//line yacctab:1 //line yacctab:1
var jsonExca = []int{ var jsonExca = []int{
@ -70,59 +74,59 @@ var jsonExca = []int{
-2, 0, -2, 0,
} }
const jsonNprod = 23 const jsonNprod = 26
const jsonPrivate = 57344 const jsonPrivate = 57344
var jsonTokenNames []string var jsonTokenNames []string
var jsonStates []string var jsonStates []string
const jsonLast = 45 const jsonLast = 50
var jsonAct = []int{ var jsonAct = []int{
12, 23, 20, 25, 23, 3, 7, 13, 3, 10, 12, 23, 26, 27, 28, 23, 3, 13, 3, 20,
21, 26, 17, 18, 19, 22, 30, 23, 22, 7, 21, 29, 17, 18, 19, 22, 7, 23, 5, 22,
1, 5, 28, 13, 3, 29, 21, 32, 17, 18, 7, 9, 31, 13, 3, 37, 21, 8, 17, 18,
19, 22, 9, 33, 6, 31, 15, 2, 8, 24, 19, 22, 32, 36, 6, 10, 35, 34, 38, 33,
4, 27, 16, 14, 11, 15, 2, 1, 24, 11, 25, 4, 30, 16, 14,
} }
var jsonPact = []int{ 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, 13, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-16, -3, 0, -1000, -1000, 12, -1000, 21, -1000, -1000, -17, -3, 1, -1000, -1000, -1000, 35, 33, 32, -1000,
-1000, -1000, 13, -1000, 19, -1000, -1000, -1000, -1000, -1000, -1000, 13, -1000,
} }
var jsonPgo = []int{ var jsonPgo = []int{
0, 2, 43, 36, 34, 0, 42, 41, 40, 39, 0, 9, 49, 40, 34, 0, 48, 47, 46, 45,
20, 43, 42,
} }
var jsonR1 = []int{ 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, 5, 5, 5, 5, 6, 6, 7, 7, 2, 2,
1, 1, 9, 2, 1, 1, 9, 9, 10,
} }
var jsonR2 = []int{ var jsonR2 = []int{
0, 1, 3, 2, 1, 3, 3, 1, 1, 1, 0, 1, 3, 2, 1, 3, 3, 1, 1, 1,
1, 1, 1, 1, 2, 3, 1, 3, 1, 2, 1, 1, 1, 1, 2, 3, 1, 3, 1, 2,
2, 1, 2, 2, 2, 1, 2, 2, 2,
} }
var jsonChk = []int{ 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, 5, -4, -5, 10, -2, -3, -6, 15, 16, 17,
-1, 13, 18, 4, -9, 19, 14, -7, -5, -1, -1, 13, 18, 4, -10, -9, 19, 20, 21, 14,
4, 14, 6, -5, -7, -5, -1, 4, 4, 4, 14, 6, -5,
} }
var jsonDef = []int{ var jsonDef = []int{
0, -2, 1, 0, 0, 3, 4, 0, 2, 0, 0, -2, 1, 0, 0, 3, 4, 0, 2, 0,
0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 5, 6, 7, 8, 9, 10, 11, 12, 13,
18, 0, 0, 21, 19, 0, 14, 0, 16, 20, 18, 0, 0, 22, 19, 20, 0, 0, 0, 14,
22, 15, 0, 17, 0, 16, 21, 25, 23, 24, 15, 0, 17,
} }
var jsonTok1 = []int{ var jsonTok1 = []int{
@ -131,7 +135,7 @@ var jsonTok1 = []int{
var jsonTok2 = []int{ var jsonTok2 = []int{
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 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{ var jsonTok3 = []int{
0, 0,
@ -489,17 +493,41 @@ jsondefault:
} }
} }
case 20: 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 jsonVAL.num = jsonS[jsonpt-0].num * -1
} }
case 21: case 22:
//line parse.y:163 //line parse.y:176
{ {
jsonVAL.num = jsonS[jsonpt-0].num jsonVAL.num = jsonS[jsonpt-0].num
} }
case 22: case 23:
//line parse.y:169 //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) 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
}