Skip to content
This repository has been archived by the owner on Oct 24, 2024. It is now read-only.

Commit

Permalink
Rules: Fix parsing of floating point numbers
Browse files Browse the repository at this point in the history
- Parse floating point numbers containing fractional and exponent
  part
- Support infinity and NaN

Closes #11.
  • Loading branch information
tindzk committed Aug 20, 2019
1 parent 77c0ecf commit ae0dc8a
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 2 deletions.
15 changes: 13 additions & 2 deletions shared/src/main/scala/toml/Rules.scala
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,19 @@ object Rules extends PlatformRules {
val integer: Parser[Value.Num] =
P(+-.? ~ integral).!.map(s => Value.Num(rmUnderscore(s).toLong))
val double: Parser[Value.Real] =
P(+-.? ~ integral ~ (fractional | exponent)).!.map(s =>
Value.Real(rmUnderscore(s).toDouble))
P(
+-.?.!.map(c => c == "-") ~ (
P("inf").map(_ => Double.PositiveInfinity) |
P("nan").map(_ => Double.NaN) |
P(integral ~ (
(fractional ~ exponent) |
fractional |
exponent
)).!.map(s => rmUnderscore(s).toDouble)
)
).map { case (neg, value) =>
if (neg) Value.Real(-value) else Value.Real(value)
}

val `true` = P("true") .map(_ => Value.Bool(true))
val `false` = P("false").map(_ => Value.Bool(false))
Expand Down
72 changes: 72 additions & 0 deletions shared/src/test/scala/toml/RulesSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,76 @@ class RulesSpec extends FunSuite with Matchers {
val example = "number = 3.14 p"
testFailure(example)
}

test("Parse floats with fractional part") {
val example =
"""flt1 = +1.0
|flt2 = 3.1415
|flt3 = -0.01
""".stripMargin

assert(testSuccess(example) == Root(List(
Node.Pair("flt1", Value.Real(+1.0)),
Node.Pair("flt2", Value.Real(3.1415)),
Node.Pair("flt3", Value.Real(-0.01)))))
}

test("Parse floats with exponent part") {
val example =
"""flt4 = 5e+22
|flt5 = 1e6
|flt6 = -2E-2
""".stripMargin

assert(testSuccess(example) == Root(List(
Node.Pair("flt4", Value.Real(5e+22)),
Node.Pair("flt5", Value.Real(1e6)),
Node.Pair("flt6", Value.Real(-2E-2)))))
}

test("Parse floats with fractional and exponent part") {
val example = "flt7 = 6.626e-34\n" +
"poly = -45.321e12"

assert(testSuccess(example) == Root(List(
Node.Pair("flt7", Value.Real(6.626e-34)),
Node.Pair("poly", Value.Real(-45.321e12)))))
}

test("Parse floats with underscores") {
val example = "flt8 = 224_617.445_991_228"

assert(testSuccess(example) == Root(List(
Node.Pair("flt8", Value.Real(224617.445991228)))))
}

test("Parse infinity float values") {
val example =
"""sf1 = inf
|sf2 = +inf
|sf3 = -inf
|""".stripMargin

assert(testSuccess(example) == Root(List(
Node.Pair("sf1", Value.Real(Double.PositiveInfinity)),
Node.Pair("sf2", Value.Real(Double.PositiveInfinity)),
Node.Pair("sf3", Value.Real(Double.NegativeInfinity)))))
}

test("Parse NaN float values") {
val example =
"""sf4 = nan
|sf5 = +nan
|sf6 = -nan
|""".stripMargin

val result = testSuccess(example).nodes
assert(result.length == 3)

// Cannot use `==` here since Double.NaN != Double.NaN
assert(result.forall {
case Node.Pair(_, Value.Real(v)) => v.equals(Double.NaN)
case _ => false
})
}
}

0 comments on commit ae0dc8a

Please sign in to comment.