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 return l.lexFalse
} }
if l.follow("inf") {
return l.lexInf
}
if l.follow("nan") {
return l.lexNan
}
if isSpace(next) { if isSpace(next) {
l.skip() l.skip()
continue continue
@@ -265,6 +273,18 @@ func (l *tomlLexer) lexFalse() tomlLexStateFn {
return l.lexRvalue 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 { func (l *tomlLexer) lexEqual() tomlLexStateFn {
l.next() l.next()
l.emit(tokenEqual) l.emit(tokenEqual)
@@ -651,7 +671,14 @@ func (l *tomlLexer) lexNumber() tomlLexStateFn {
if r == '+' || r == '-' { if r == '+' || r == '-' {
l.next() l.next()
if l.follow("inf") {
return l.lexInf
} }
if l.follow("nan") {
return l.lexNan
}
}
pointSeen := false pointSeen := false
expSeen := false expSeen := false
digitSeen := false digitSeen := false
+8
View File
@@ -5,6 +5,7 @@ package toml
import ( import (
"errors" "errors"
"fmt" "fmt"
"math"
"reflect" "reflect"
"regexp" "regexp"
"strconv" "strconv"
@@ -243,6 +244,13 @@ func (p *tomlParser) parseRvalue() interface{} {
return true return true
case tokenFalse: case tokenFalse:
return false return false
case tokenInf:
if tok.val[0] == '-' {
return math.Inf(-1)
}
return math.Inf(1)
case tokenNan:
return math.NaN()
case tokenInteger: case tokenInteger:
cleanedVal := cleanupNumberToken(tok.val) cleanedVal := cleanupNumberToken(tok.val)
var err error var err error
+20
View File
@@ -2,6 +2,7 @@ package toml
import ( import (
"fmt" "fmt"
"math"
"reflect" "reflect"
"testing" "testing"
"time" "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) { func TestHexIntegers(t *testing.T) {
tree, err := Load(`a = 0xDEADBEEF`) tree, err := Load(`a = 0xDEADBEEF`)
assertTree(t, tree, err, map[string]interface{}{"a": int64(3735928559)}) assertTree(t, tree, err, map[string]interface{}{"a": int64(3735928559)})
+4
View File
@@ -23,6 +23,8 @@ const (
tokenTrue tokenTrue
tokenFalse tokenFalse
tokenFloat tokenFloat
tokenInf
tokenNan
tokenEqual tokenEqual
tokenLeftBracket tokenLeftBracket
tokenRightBracket tokenRightBracket
@@ -55,6 +57,8 @@ var tokenTypeNames = []string{
"True", "True",
"False", "False",
"Float", "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 // Ensure a round float does contain a decimal point. Otherwise feeding
// the output back to the parser would convert to an integer. // the output back to the parser would convert to an integer.
if math.Trunc(value) == value { 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: case string:
return "\"" + encodeTomlString(value) + "\"", nil return "\"" + encodeTomlString(value) + "\"", nil
case []byte: 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) { func BenchmarkTreeToTomlString(b *testing.B) {
toml, err := Load(sampleHard) toml, err := Load(sampleHard)
if err != nil { if err != nil {