diff --git a/decoder.go b/decoder.go index 1b76d93..dec5d5f 100644 --- a/decoder.go +++ b/decoder.go @@ -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))) diff --git a/decoder_test.go b/decoder_test.go index 33a2292..8648317 100644 --- a/decoder_test.go +++ b/decoder_test.go @@ -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, diff --git a/json/lex.go b/json/lex.go index e0864bb..3ddce6f 100644 --- a/json/lex.go +++ b/json/lex.go @@ -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 '-': diff --git a/json/parse.y b/json/parse.y index 8d3a7e0..dc8af85 100644 --- a/json/parse.y +++ b/json/parse.y @@ -22,12 +22,12 @@ import ( %type int %type number object pair value %type array elements members -%type frac +%type exp frac %token NUMBER %token COLON COMMA IDENTIFIER EQUAL NEWLINE STRING %token LEFTBRACE RIGHTBRACE LEFTBRACKET RIGHTBRACKET -%token TRUE FALSE NULL MINUS PERIOD +%token 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 { diff --git a/json/y.go b/json/y.go index c4a6090..11d4671 100644 --- a/json/y.go +++ b/json/y.go @@ -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) } diff --git a/test-fixtures/scientific.hcl b/test-fixtures/scientific.hcl new file mode 100644 index 0000000..156ed0f --- /dev/null +++ b/test-fixtures/scientific.hcl @@ -0,0 +1,3 @@ +a = 1e-10 +b = 1e+10 +c = 1e10 diff --git a/test-fixtures/scientific.json b/test-fixtures/scientific.json new file mode 100644 index 0000000..eb29895 --- /dev/null +++ b/test-fixtures/scientific.json @@ -0,0 +1,5 @@ +{ + "a": 1e-10, + "b": 1e+10, + "c": 1e10 +}