From c42c3365f30b4819587b5aa0b77bcb064d08ec1f Mon Sep 17 00:00:00 2001 From: Wendell Sun Date: Tue, 28 Sep 2021 07:11:21 +0800 Subject: [PATCH] Support unmarshaling up to uint64 (#608) --- marshal.go | 2 +- parser.go | 47 +++++++++++++++++++++++------------------------ parser_test.go | 7 +++++++ 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/marshal.go b/marshal.go index 3443c354..57127304 100644 --- a/marshal.go +++ b/marshal.go @@ -1113,7 +1113,7 @@ func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}, mval1 *ref return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) } - if val.Convert(reflect.TypeOf(int(1))).Int() < 0 { + if val.Type().Kind() != reflect.Uint64 && val.Convert(reflect.TypeOf(int(1))).Int() < 0 { return reflect.ValueOf(nil), fmt.Errorf("%v(%T) is negative so does not fit in %v", tval, tval, mtype.String()) } if reflect.Indirect(reflect.New(mtype)).OverflowUint(val.Convert(reflect.TypeOf(uint64(0))).Uint()) { diff --git a/parser.go b/parser.go index f5e1a44f..b3726d0d 100644 --- a/parser.go +++ b/parser.go @@ -293,42 +293,41 @@ func (p *tomlParser) parseRvalue() interface{} { return math.NaN() case tokenInteger: cleanedVal := cleanupNumberToken(tok.val) - var err error - var val int64 + base := 10 + s := cleanedVal + checkInvalidUnderscore := numberContainsInvalidUnderscore if len(cleanedVal) >= 3 && cleanedVal[0] == '0' { switch cleanedVal[1] { case 'x': - err = hexNumberContainsInvalidUnderscore(tok.val) - if err != nil { - p.raiseError(tok, "%s", err) - } - val, err = strconv.ParseInt(cleanedVal[2:], 16, 64) + checkInvalidUnderscore = hexNumberContainsInvalidUnderscore + base = 16 case 'o': - err = numberContainsInvalidUnderscore(tok.val) - if err != nil { - p.raiseError(tok, "%s", err) - } - val, err = strconv.ParseInt(cleanedVal[2:], 8, 64) + base = 8 case 'b': - err = numberContainsInvalidUnderscore(tok.val) - if err != nil { - p.raiseError(tok, "%s", err) - } - val, err = strconv.ParseInt(cleanedVal[2:], 2, 64) + base = 2 default: panic("invalid base") // the lexer should catch this first } - } else { - err = numberContainsInvalidUnderscore(tok.val) - if err != nil { - p.raiseError(tok, "%s", err) - } - val, err = strconv.ParseInt(cleanedVal, 10, 64) + s = cleanedVal[2:] } + + err := checkInvalidUnderscore(tok.val) if err != nil { p.raiseError(tok, "%s", err) } - return val + + var val interface{} + val, err = strconv.ParseInt(s, base, 64) + if err == nil { + return val + } + + if s[0] != '-' { + if val, err = strconv.ParseUint(s, base, 64); err == nil { + return val + } + } + p.raiseError(tok, "%s", err) case tokenFloat: err := numberContainsInvalidUnderscore(tok.val) if err != nil { diff --git a/parser_test.go b/parser_test.go index a2338b71..f63cb50d 100644 --- a/parser_test.go +++ b/parser_test.go @@ -1162,3 +1162,10 @@ str3 = """\ t.Errorf("expected '%s', got '%s'", expected, got) } } + +func TestUint(t *testing.T) { + tree, err := Load("hello = 18446744073709551615") + assertTree(t, tree, err, map[string]interface{}{ + "hello": uint64(math.MaxUint64), + }) +}