From 59a6672576ba4a630eb58f186db35438d17c86a3 Mon Sep 17 00:00:00 2001 From: Tony Morris Date: Wed, 27 Jun 2012 17:47:42 +1000 Subject: [PATCH] number --- .../scala/com/ephox/argonaut/Argonaut.scala | 1 + .../scala/com/ephox/argonaut/DecodeJson.scala | 8 +- .../scala/com/ephox/argonaut/EncodeJson.scala | 8 +- src/main/scala/com/ephox/argonaut/Json.scala | 8 +- .../scala/com/ephox/argonaut/JsonNumber.scala | 123 +++++------------- .../scala/com/ephox/argonaut/JsonParser.scala | 6 +- src/test/scala/com/ephox/argonaut/Data.scala | 6 +- 7 files changed, 42 insertions(+), 118 deletions(-) diff --git a/src/main/scala/com/ephox/argonaut/Argonaut.scala b/src/main/scala/com/ephox/argonaut/Argonaut.scala index be3e3daf..d43cce13 100644 --- a/src/main/scala/com/ephox/argonaut/Argonaut.scala +++ b/src/main/scala/com/ephox/argonaut/Argonaut.scala @@ -10,6 +10,7 @@ DecodeJsons with EncodeJsons with Jsons with JsonIdentitys with +JsonNumbers with PrettyParamss with Shifts with ShiftHistorys with diff --git a/src/main/scala/com/ephox/argonaut/DecodeJson.scala b/src/main/scala/com/ephox/argonaut/DecodeJson.scala index efd4acab..a4f81f17 100644 --- a/src/main/scala/com/ephox/argonaut/DecodeJson.scala +++ b/src/main/scala/com/ephox/argonaut/DecodeJson.scala @@ -248,10 +248,10 @@ trait DecodeJsons { decodej(x => if(x.isNull) Some(Float.NaN) else x.number map (_.toFloat), "Float") implicit def IntDecodeJson: DecodeJson[Int] = - decodej(_.number map (_.toInt), "Int") + decodej(_.string flatMap (s => try { Some(s.toInt) } catch { case _ => None }), "Int") implicit def LongDecodeJson: DecodeJson[Long] = - decodej(_.number map (_.toLong), "Long") + decodej(_.string flatMap (s => try { Some(s.toLong) } catch { case _ => None }), "Long") implicit def BooleanDecodeJson: DecodeJson[Boolean] = decodej(_.bool, "Boolean") @@ -266,10 +266,10 @@ trait DecodeJsons { decodej(_.number map (_.toFloat), "java.lang.Float") implicit def JIntegerDecodeJson: DecodeJson[java.lang.Integer] = - decodej(_.number map (_.toInt), "java.lang.Integer") + decodej(_.string flatMap (s => try { Some(s.toInt) } catch { case _ => None }), "java.lang.Integer") implicit def JLongDecodeJson: DecodeJson[java.lang.Long] = - decodej(_.number map (_.toLong), "java.lang.Long") + decodej(_.string flatMap (s => try { Some(s.toLong) } catch { case _ => None }), "java.lang.Long") implicit def JBooleanDecodeJson: DecodeJson[java.lang.Boolean] = decodej(_.bool map (q => q), "java.lang.Boolean") diff --git a/src/main/scala/com/ephox/argonaut/EncodeJson.scala b/src/main/scala/com/ephox/argonaut/EncodeJson.scala index ea3d441d..2157eead 100644 --- a/src/main/scala/com/ephox/argonaut/EncodeJson.scala +++ b/src/main/scala/com/ephox/argonaut/EncodeJson.scala @@ -53,10 +53,10 @@ trait EncodeJsons { EncodeJson(a => jDouble(a), "Float") implicit def IntEncodeJson: EncodeJson[Int] = - EncodeJson(a => jIntegral(a), "Int") + EncodeJson(a => jString(a.toString), "Int") implicit def LongEncodeJson: EncodeJson[Long] = - EncodeJson(a => jIntegral(a), "Long") + EncodeJson(a => jString(a.toString), "Long") implicit def BooleanEncodeJson: EncodeJson[Boolean] = EncodeJson(jBool, "Boolean") @@ -71,10 +71,10 @@ trait EncodeJsons { EncodeJson(a => jDouble(a.floatValue.toDouble), "java.lang.Float") implicit def JIntegerEncodeJson: EncodeJson[java.lang.Integer] = - EncodeJson(a => jIntegral(a.intValue), "java.lang.Integer") + EncodeJson(a => jString(a.toString), "java.lang.Integer") implicit def JLongEncodeJson: EncodeJson[java.lang.Long] = - EncodeJson(a => jIntegral(a.longValue), "java.lang.Long") + EncodeJson(a => jString(a.toString), "java.lang.Long") implicit def JBooleanEncodeJson: EncodeJson[java.lang.Boolean] = EncodeJson(a => jBool(a.booleanValue), "java.lang.Boolean") diff --git a/src/main/scala/com/ephox/argonaut/Json.scala b/src/main/scala/com/ephox/argonaut/Json.scala index 48bcb3f5..01e8eb5b 100644 --- a/src/main/scala/com/ephox/argonaut/Json.scala +++ b/src/main/scala/com/ephox/argonaut/Json.scala @@ -486,13 +486,7 @@ trait Jsons { JNumber(_) /** - * Construct a JSON value that is an integral number. - */ - val jIntegral: BigInt => Json = - i => JNumber(JsonNumber.jIntegralNumber(i)) - - /** - * Construct a JSON value that is an integral number. + * Construct a JSON value that is a double. */ val jDouble: Double => Json = d => JNumber(JsonNumber(d)) diff --git a/src/main/scala/com/ephox/argonaut/JsonNumber.scala b/src/main/scala/com/ephox/argonaut/JsonNumber.scala index a7490a05..0fdd49b6 100644 --- a/src/main/scala/com/ephox/argonaut/JsonNumber.scala +++ b/src/main/scala/com/ephox/argonaut/JsonNumber.scala @@ -3,144 +3,81 @@ package argonaut import scalaz._, Scalaz._ +/** + * A value representation a JSON number according to ECMA-262. + * + * @author Tony Morris + */ sealed trait JsonNumber { - def toEither: Either[BigInt, Double] = - this match { - case IntJsonNumber(i) => Left(i) - case DoubleJsonNumber(d) => Right(d) - } + val toDouble: Double def +(n: JsonNumber): JsonNumber = - binary((x, y) => IntJsonNumber(x + y), (x, y) => DoubleJsonNumber(x + y), n) + binary(_ + _, n) def -(n: JsonNumber): JsonNumber = - binary((x, y) => IntJsonNumber(x - y), (x, y) => DoubleJsonNumber(x - y), n) + binary(_ - _, n) def *(n: JsonNumber): JsonNumber = - binary((x, y) => IntJsonNumber(x * y), (x, y) => DoubleJsonNumber(x * y), n) + binary(_ * _, n) def compare(n: JsonNumber): Ordering = - binary(Order[BigInt].order(_, _), Order[Double].order(_, _), n) + Order[Double].order(toDouble, n.toDouble) def abs: JsonNumber = - this match { - case IntJsonNumber(i) => IntJsonNumber(i.abs) - case DoubleJsonNumber(d) => DoubleJsonNumber(d.abs) - } + JsonNumber(toDouble.abs) def unary_- : JsonNumber = - this match { - case IntJsonNumber(i) => IntJsonNumber(-i) - case DoubleJsonNumber(d) => DoubleJsonNumber(-d) - } + JsonNumber(-toDouble) def signum: JsonNumber = - this match { - case IntJsonNumber(i) => IntJsonNumber(i.signum) - case DoubleJsonNumber(d) => DoubleJsonNumber(d.signum) - } + JsonNumber(toDouble.signum) def round: JsonNumber = - this match { - case IntJsonNumber(i) => IntJsonNumber(i) - case DoubleJsonNumber(d) => DoubleJsonNumber(d.round) - } + JsonNumber(toDouble.round) def ceil: JsonNumber = - this match { - case IntJsonNumber(i) => IntJsonNumber(i) - case DoubleJsonNumber(d) => DoubleJsonNumber(d.ceil) - } + JsonNumber(toDouble.ceil) def floor: JsonNumber = - this match { - case IntJsonNumber(i) => IntJsonNumber(i) - case DoubleJsonNumber(d) => DoubleJsonNumber(d.floor) - } - - def toDouble: Double = - this match { - case IntJsonNumber(i) => i.toDouble - case DoubleJsonNumber(d) => d - } + JsonNumber(toDouble.floor) def toFloat: Float = - this match { - case IntJsonNumber(i) => i.toFloat - case DoubleJsonNumber(d) => d.toFloat - } + toDouble.toFloat def toLong: Long = - this match { - case IntJsonNumber(i) => i.toLong - case DoubleJsonNumber(d) => d.toLong - } + toDouble.toLong def toInt: Int = - this match { - case IntJsonNumber(i) => i.toInt - case DoubleJsonNumber(d) => d.toInt - } + toDouble.toInt override def equals(a: Any): Boolean = - a.isInstanceOf[JsonNumber] && binary(_ == _, _ == _, a.asInstanceOf[JsonNumber]) + a.isInstanceOf[JsonNumber] && { toDouble == a.asInstanceOf[JsonNumber].toDouble } override def toString: String = - this match { - case IntJsonNumber(i) => i.toString - case DoubleJsonNumber(d) => d.toString - } + toDouble.toString private def binary[A]( - i: (BigInt, BigInt) => A - , d: (Double, Double) => A + i: (Double, Double) => Double , n: JsonNumber - ): A = - this match { - case IntJsonNumber(i1) => n match { - case IntJsonNumber(i2) => i(i1, i2) - case DoubleJsonNumber(d2) => i(i1, BigInt(d2.toLong)) - } - case DoubleJsonNumber(d1) => n match { - case IntJsonNumber(i2) => i(BigInt(d1.toLong), i2) - case DoubleJsonNumber(d2) => d(d1, d2) - } - } + ): JsonNumber = + JsonNumber(i(toDouble, n.toDouble)) } -private case class DoubleJsonNumber(d: Double) extends JsonNumber -private case class IntJsonNumber(i: BigInt) extends JsonNumber object JsonNumber extends JsonNumbers { def apply(d: Double): JsonNumber = - DoubleJsonNumber(d) + new JsonNumber { + val toDouble = d + } } trait JsonNumbers { - def jIntegralNumber(i: BigInt): JsonNumber = - IntJsonNumber(i) - - val jDoubleL: JsonNumber @?> Double = - PLens { - case DoubleJsonNumber(d) => Some(Store(DoubleJsonNumber(_), d)) - case IntJsonNumber(_) => None - } - - val jIntegralL: JsonNumber @?> BigInt = - PLens { - case DoubleJsonNumber(_) => None - case IntJsonNumber(i) => Some(Store(IntJsonNumber(_), i)) - } - implicit val JsonNumberInstances: Order[JsonNumber] with Show[JsonNumber] with Monoid[JsonNumber] = new Order[JsonNumber] with Show[JsonNumber] with Monoid[JsonNumber] { - def zero = DoubleJsonNumber(0D) + def zero = JsonNumber(Monoid[Double].zero) def append(x: JsonNumber, y: => JsonNumber) = - x + y + JsonNumber(Monoid[Double].append(x.toDouble, y.toDouble)) def show(x: JsonNumber) = - x match { - case IntJsonNumber(i) => implicitly[Show[BigInt]].show(i) - case DoubleJsonNumber(d) => implicitly[Show[Double]].show(d) - } + Show[Double].show(x.toDouble) def order(x: JsonNumber, y: JsonNumber) = x compare y } diff --git a/src/main/scala/com/ephox/argonaut/JsonParser.scala b/src/main/scala/com/ephox/argonaut/JsonParser.scala index e1df388b..8ebff69e 100644 --- a/src/main/scala/com/ephox/argonaut/JsonParser.scala +++ b/src/main/scala/com/ephox/argonaut/JsonParser.scala @@ -75,11 +75,7 @@ class JsonParser extends Parsers { def hex = digit | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' - def number: Parser[JsonNumber] = { - val i = (int ||| intexp) ^^ (q => jIntegralNumber(BigInt(q.mkString))) - val d = (intfrac ||| intfracexp) ^^ {q => JsonNumber(q.mkString.toDouble)} - i ||| d - } + def number = (int ||| intfrac ||| intexp ||| intfracexp) ^^ {q => JsonNumber(q.mkString.toDouble)} def intexp = int ~ exp ^^ {case a ~ b => a ++ b} diff --git a/src/test/scala/com/ephox/argonaut/Data.scala b/src/test/scala/com/ephox/argonaut/Data.scala index 03b21d19..1e2d7549 100644 --- a/src/test/scala/com/ephox/argonaut/Data.scala +++ b/src/test/scala/com/ephox/argonaut/Data.scala @@ -5,15 +5,11 @@ import scalaz._, Scalaz._ import org.scalacheck.Arbitrary.arbitrary import org.scalacheck.Gen.{frequency, choose, listOfN, value, oneOf} import Json._ -import JsonNumber._ import org.scalacheck.{Gen, Arbitrary} object Data { implicit def ArbitraryJsonNumber: Arbitrary[JsonNumber] = - Arbitrary(arbitrary[Either[BigInt, Double]] map { - case Left(i) => jIntegralNumber(i) - case Right(d) => JsonNumber(d) - }) + Arbitrary(arbitrary[Double] map (JsonNumber(_))) implicit def ArbitraryJson: Arbitrary[Json] = { val n = value(jNull)