Skip to content

Commit

Permalink
number
Browse files Browse the repository at this point in the history
  • Loading branch information
tonymorris committed Jun 27, 2012
1 parent a7f19a7 commit 59a6672
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 118 deletions.
1 change: 1 addition & 0 deletions src/main/scala/com/ephox/argonaut/Argonaut.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ DecodeJsons with
EncodeJsons with
Jsons with
JsonIdentitys with
JsonNumbers with
PrettyParamss with
Shifts with
ShiftHistorys with
Expand Down
8 changes: 4 additions & 4 deletions src/main/scala/com/ephox/argonaut/DecodeJson.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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")
Expand Down
8 changes: 4 additions & 4 deletions src/main/scala/com/ephox/argonaut/EncodeJson.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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")
Expand Down
8 changes: 1 addition & 7 deletions src/main/scala/com/ephox/argonaut/Json.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
123 changes: 30 additions & 93 deletions src/main/scala/com/ephox/argonaut/JsonNumber.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
6 changes: 1 addition & 5 deletions src/main/scala/com/ephox/argonaut/JsonParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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}

Expand Down
6 changes: 1 addition & 5 deletions src/test/scala/com/ephox/argonaut/Data.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 59a6672

Please sign in to comment.