Add support for special float values (inf and nan) (#210)

This commit is contained in:
Jelte Fennema
2018-01-18 23:10:55 +01:00
committed by Thomas Pelletier
parent a1e8a8d702
commit 778c285afa
6 changed files with 79 additions and 2 deletions
+27
View File
@@ -204,6 +204,14 @@ func (l *tomlLexer) lexRvalue() tomlLexStateFn {
return l.lexFalse
}
if l.follow("inf") {
return l.lexInf
}
if l.follow("nan") {
return l.lexNan
}
if isSpace(next) {
l.skip()
continue
@@ -265,6 +273,18 @@ func (l *tomlLexer) lexFalse() tomlLexStateFn {
return l.lexRvalue
}
func (l *tomlLexer) lexInf() tomlLexStateFn {
l.fastForward(3)
l.emit(tokenInf)
return l.lexRvalue
}
func (l *tomlLexer) lexNan() tomlLexStateFn {
l.fastForward(3)
l.emit(tokenNan)
return l.lexRvalue
}
func (l *tomlLexer) lexEqual() tomlLexStateFn {
l.next()
l.emit(tokenEqual)
@@ -651,7 +671,14 @@ func (l *tomlLexer) lexNumber() tomlLexStateFn {
if r == '+' || r == '-' {
l.next()
if l.follow("inf") {
return l.lexInf
}
if l.follow("nan") {
return l.lexNan
}
}
pointSeen := false
expSeen := false
digitSeen := false
+8
View File
@@ -5,6 +5,7 @@ package toml
import (
"errors"
"fmt"
"math"
"reflect"
"regexp"
"strconv"
@@ -243,6 +244,13 @@ func (p *tomlParser) parseRvalue() interface{} {
return true
case tokenFalse:
return false
case tokenInf:
if tok.val[0] == '-' {
return math.Inf(-1)
}
return math.Inf(1)
case tokenNan:
return math.NaN()
case tokenInteger:
cleanedVal := cleanupNumberToken(tok.val)
var err error
+20
View File
@@ -2,6 +2,7 @@ package toml
import (
"fmt"
"math"
"reflect"
"testing"
"time"
@@ -93,6 +94,25 @@ func TestSimpleNumbers(t *testing.T) {
})
}
func TestSpecialFloats(t *testing.T) {
tree, err := Load(`
normalinf = inf
plusinf = +inf
minusinf = -inf
normalnan = nan
plusnan = +nan
minusnan = -nan
`)
assertTree(t, tree, err, map[string]interface{}{
"normalinf": math.Inf(1),
"plusinf": math.Inf(1),
"minusinf": math.Inf(-1),
"normalnan": math.NaN(),
"plusnan": math.NaN(),
"minusnan": math.NaN(),
})
}
func TestHexIntegers(t *testing.T) {
tree, err := Load(`a = 0xDEADBEEF`)
assertTree(t, tree, err, map[string]interface{}{"a": int64(3735928559)})
+4
View File
@@ -23,6 +23,8 @@ const (
tokenTrue
tokenFalse
tokenFloat
tokenInf
tokenNan
tokenEqual
tokenLeftBracket
tokenRightBracket
@@ -55,6 +57,8 @@ var tokenTypeNames = []string{
"True",
"False",
"Float",
"Inf",
"NaN",
"=",
"[",
"]",
+2 -2
View File
@@ -54,9 +54,9 @@ func tomlValueStringRepresentation(v interface{}, indent string, arraysOneElemen
// Ensure a round float does contain a decimal point. Otherwise feeding
// the output back to the parser would convert to an integer.
if math.Trunc(value) == value {
return strconv.FormatFloat(value, 'f', 1, 32), nil
return strings.ToLower(strconv.FormatFloat(value, 'f', 1, 32)), nil
}
return strconv.FormatFloat(value, 'f', -1, 32), nil
return strings.ToLower(strconv.FormatFloat(value, 'f', -1, 32)), nil
case string:
return "\"" + encodeTomlString(value) + "\"", nil
case []byte:
+18
View File
@@ -309,6 +309,24 @@ func TestTreeWriteToFloat(t *testing.T) {
}
}
func TestTreeWriteToSpecialFloat(t *testing.T) {
expected := `a = +inf
b = -inf
c = nan`
tree, err := Load(expected)
if err != nil {
t.Fatal(err)
}
str, err := tree.ToTomlString()
if err != nil {
t.Fatal(err)
}
if strings.TrimSpace(str) != strings.TrimSpace(expected) {
t.Fatalf("Expected:\n%s\nGot:\n%s", expected, str)
}
}
func BenchmarkTreeToTomlString(b *testing.B) {
toml, err := Load(sampleHard)
if err != nil {