Skip to content
This repository was archived by the owner on Jun 15, 2023. It is now read-only.

Commit d2d8bbd

Browse files
authored
Merge pull request #22 from garyb/hugeint
Use HugeInt for Integer
2 parents d252fc3 + 521d58a commit d2d8bbd

File tree

8 files changed

+89
-58
lines changed

8 files changed

+89
-58
lines changed

bower.json

+4-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
"purescript-newtype": "^2.0.0",
2424
"purescript-parsing": "^4.1.0",
2525
"purescript-precise": "^2.0.0",
26-
"purescript-profunctor-lenses": "^3.2.0",
27-
"purescript-strongcheck": "^3.1.0"
26+
"purescript-profunctor-lenses": "^3.2.0"
27+
},
28+
"devDependencies": {
29+
"purescript-quickcheck": "^4.4.0"
2830
}
2931
}

src/Data/Json/Extended.purs

+24-8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module Data.Json.Extended
55
, boolean
66
, integer
77
, decimal
8+
, number
89
, string
910
, map
1011
, map'
@@ -24,6 +25,7 @@ module Data.Json.Extended
2425
, _Boolean
2526
, _Integer
2627
, _Decimal
28+
, _Number
2729
, _Array
2830
, _Map
2931
, _Map'
@@ -32,26 +34,25 @@ module Data.Json.Extended
3234
import Prelude hiding (map)
3335

3436
import Control.Lazy as Lazy
35-
3637
import Data.Argonaut as JS
3738
import Data.Bitraversable (bitraverse)
3839
import Data.Either as E
3940
import Data.Functor as F
4041
import Data.Functor.Mu as Mu
42+
import Data.HugeInt as HI
4143
import Data.HugeNum as HN
4244
import Data.Json.Extended.Signature as Sig
45+
import Data.Json.Extended.Signature hiding (getType) as Exports
4346
import Data.Json.Extended.Type (EJsonType)
4447
import Data.Lens (Prism', preview, prism')
4548
import Data.Map as Map
4649
import Data.Maybe as M
4750
import Data.StrMap as SM
4851
import Data.Traversable (for)
4952
import Data.Tuple as T
50-
import Data.Json.Extended.Signature hiding (getType) as Exports
51-
5253
import Matryoshka (class Corecursive, class Recursive, anaM, cata, embed, project)
53-
54-
import Test.StrongCheck.Gen as Gen
54+
import Control.Monad.Gen (class MonadGen)
55+
import Control.Monad.Rec.Class (class MonadRec)
5556
import Text.Parsing.Parser as P
5657

5758
type EJson = Mu.Mu Sig.EJsonF
@@ -62,7 +63,13 @@ decodeEJson = anaM Sig.decodeJsonEJsonF
6263
encodeEJson t. Recursive t Sig.EJsonF t JS.Json
6364
encodeEJson = cata Sig.encodeJsonEJsonF
6465

65-
arbitraryEJsonOfSize t. Corecursive t Sig.EJsonF Gen.Size Gen.Gen t
66+
arbitraryEJsonOfSize
67+
m t
68+
. MonadGen m
69+
MonadRec m
70+
Corecursive t Sig.EJsonF
71+
Int
72+
m t
6673
arbitraryEJsonOfSize = anaM Sig.arbitraryEJsonF
6774

6875
renderEJson t. Recursive t Sig.EJsonF t String
@@ -78,12 +85,15 @@ null = embed Sig.Null
7885
boolean t. Corecursive t Sig.EJsonF Boolean t
7986
boolean = embed <<< Sig.Boolean
8087

81-
integer t. Corecursive t Sig.EJsonF Int t
88+
integer t. Corecursive t Sig.EJsonF HI.HugeInt t
8289
integer = embed <<< Sig.Integer
8390

8491
decimal t. Corecursive t Sig.EJsonF HN.HugeNum t
8592
decimal = embed <<< Sig.Decimal
8693

94+
number t. Corecursive t Sig.EJsonF E.Either HI.HugeInt HN.HugeNum t
95+
number = embed <<< E.either Sig.Integer Sig.Decimal
96+
8797
string t. Corecursive t Sig.EJsonF String t
8898
string = embed <<< Sig.String
8999

@@ -116,7 +126,7 @@ _Boolean = prism' boolean $ project >>> case _ of
116126
Sig.Boolean b → M.Just b
117127
_ → M.Nothing
118128

119-
_Integer t. Corecursive t Sig.EJsonF Recursive t Sig.EJsonF Prism' t Int
129+
_Integer t. Corecursive t Sig.EJsonF Recursive t Sig.EJsonF Prism' t HI.HugeInt
120130
_Integer = prism' integer $ project >>> case _ of
121131
Sig.Integer i → M.Just i
122132
_ → M.Nothing
@@ -126,6 +136,12 @@ _Decimal = prism' decimal $ project >>> case _ of
126136
Sig.Decimal d → M.Just d
127137
_ → M.Nothing
128138

139+
_Number t. Corecursive t Sig.EJsonF Recursive t Sig.EJsonF Prism' t (E.Either HI.HugeInt HN.HugeNum)
140+
_Number = prism' number $ project >>> case _ of
141+
Sig.Integer i → M.Just (E.Left i)
142+
Sig.Decimal d → M.Just (E.Right d)
143+
_ → M.Nothing
144+
129145
_Array t. Corecursive t Sig.EJsonF Recursive t Sig.EJsonF Prism' t (Array t)
130146
_Array = prism' array $ project >>> case _ of
131147
Sig.Array xs → M.Just xs

src/Data/Json/Extended/Signature/Core.purs

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Data.Bifunctor as BF
1010
import Data.Eq (class Eq1)
1111
import Data.Foldable as F
1212
import Data.HugeNum as HN
13+
import Data.HugeInt as HI
1314
import Data.Json.Extended.Type as JT
1415
import Data.List as L
1516
import Data.Map as M
@@ -25,7 +26,7 @@ data EJsonF a
2526
= Null
2627
| String String
2728
| Boolean Boolean
28-
| Integer Int
29+
| Integer HI.HugeInt
2930
| Decimal HN.HugeNum
3031
| Array (Array a)
3132
| Map (EJsonMap a)

src/Data/Json/Extended/Signature/Gen.purs

+13-11
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,29 @@ module Data.Json.Extended.Signature.Gen
44

55
import Prelude
66

7+
import Control.Monad.Gen (class MonadGen)
8+
import Control.Monad.Gen as Gen
9+
import Control.Monad.Rec.Class (class MonadRec)
710
import Data.Array as A
11+
import Data.HugeInt as HI
812
import Data.HugeNum as HN
913
import Data.Json.Extended.Signature.Core (EJsonF(..), EJsonMap(..))
14+
import Data.NonEmpty ((:|))
15+
import Data.String.Gen as GenS
1016
import Data.Tuple as T
11-
1217
import Matryoshka (CoalgebraM)
1318

14-
import Test.StrongCheck.Arbitrary as SC
15-
import Test.StrongCheck.Gen as Gen
16-
17-
arbitraryEJsonF CoalgebraM Gen.Gen EJsonF Int
19+
arbitraryEJsonF m. MonadGen m MonadRec m CoalgebraM m EJsonF Int
1820
arbitraryEJsonF 0 =
19-
Gen.oneOf (pure Null)
20-
[ map Boolean SC.arbitrary
21-
, map Integer SC.arbitrary
22-
, map Decimal $ map HN.fromNumber SC.arbitrary
23-
, map String SC.arbitrary
21+
Gen.oneOf $ pure Null :|
22+
[ Boolean <$> Gen.chooseBool
23+
, Integer <<< HI.fromInt <$> Gen.chooseInt (-1000000) 1000000
24+
, Decimal <<< HN.fromNumber <$> Gen.chooseFloat (-1000000.0) 1000000.0
25+
, String <$> GenS.genUnicodeString
2426
]
2527
arbitraryEJsonF n = do
2628
len ← Gen.chooseInt 0 $ n - 1
27-
Gen.oneOf (arbitraryEJsonF 0)
29+
Gen.oneOf $ arbitraryEJsonF 0 :|
2830
[ pure $ Array $ A.replicate len $ n - 1
2931
, pure $ Map $ EJsonMap $ A.replicate len $ T.Tuple (n - 1) (n - 1)
3032
]

src/Data/Json/Extended/Signature/Json.purs

+3-4
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,25 @@ module Data.Json.Extended.Signature.Json where
33
import Prelude
44

55
import Control.Alt ((<|>))
6-
76
import Data.Argonaut.Core as JS
87
import Data.Argonaut.Decode (class DecodeJson, decodeJson, (.?))
98
import Data.Argonaut.Encode (encodeJson)
109
import Data.Bifunctor (lmap)
1110
import Data.Either as E
11+
import Data.HugeInt as HI
1212
import Data.HugeNum as HN
1313
import Data.Int as Int
1414
import Data.Json.Extended.Signature.Core (EJsonF(..), EJsonMap(..))
1515
import Data.Maybe as M
1616
import Data.StrMap as SM
1717
import Data.Traversable as TR
18-
1918
import Matryoshka (Algebra, CoalgebraM)
2019

2120
encodeJsonEJsonF Algebra EJsonF JS.Json
2221
encodeJsonEJsonF = case _ of
2322
NullJS.jsonNull
2423
Boolean b → encodeJson b
25-
Integer i → encodeJson i
24+
Integer i → encodeJson $ HN.toNumber $ HI.toHugeNum i -- TODO: bug in HI.toInt
2625
Decimal a → encodeJson $ HN.toNumber a
2726
String str → encodeJson str
2827
Array xs → encodeJson xs
@@ -40,7 +39,7 @@ decodeJsonEJsonF =
4039
where
4140
decodeNumber Number EJsonF JS.Json
4241
decodeNumber a = case Int.fromNumber a of
43-
M.Just i → Integer i
42+
M.Just i → Integer $ HI.fromInt i
4443
M.NothingDecimal $ HN.fromNumber a
4544

4645
decodeArray JS.JArray E.Either String (EJsonF JS.Json)

src/Data/Json/Extended/Signature/Parse.purs

+21-10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ module Data.Json.Extended.Signature.Parse
44
, parseBooleanLiteral
55
, parseDecimalLiteral
66
, parseIntLiteral
7+
, parseHugeIntLiteral
78
, parseStringLiteral
89
, parseArrayLiteral
910
, parseMapLiteral
@@ -16,6 +17,7 @@ import Control.Alt ((<|>))
1617
import Data.Array as A
1718
import Data.Foldable as F
1819
import Data.HugeNum as HN
20+
import Data.HugeInt as HI
1921
import Data.Int as Int
2022
import Data.Json.Extended.Signature.Core (EJsonF(..), EJsonMap(..))
2123
import Data.List as L
@@ -104,13 +106,20 @@ parse1000
104106
hundreds x y z = x * 100 + y * 10 + z
105107
tens x y = x * 10 + y
106108

109+
-- | This is used for parsing both `Int` and `HugeInt` values so has some extra
110+
-- | arguments. The `n` value should be 10 in the appropriate type, used to
111+
-- | move the place of each digit that is parsed. The `Int -> n` function
112+
-- | should convert a digit to the appropriate type. The `Int` provided will
113+
-- | always be in the range 0 to 9 inclusive.
107114
parseNat
108-
m
115+
m n
109116
. Monad m
110-
P.ParserT String m Int
111-
parseNat =
112-
A.some parseDigit
113-
<#> F.foldl (\a i → a * 10 + i) 0
117+
Semiring n
118+
n
119+
(Int n)
120+
P.ParserT String m n
121+
parseNat ten digit =
122+
F.foldl (\a i → a * ten + digit i) zero <$> A.some parseDigit
114123

115124
parseNegative
116125
m a
@@ -158,7 +167,7 @@ parsePositiveScientific
158167
P.ParserT String m HN.HugeNum
159168
parsePositiveScientific = do
160169
let ten = HN.fromNumber 10.0
161-
lhs ← PC.try $ fromInt <$> parseNat <* PS.string "."
170+
lhs ← PC.try $ parseNat ten fromInt <* PS.string "."
162171
rhs ← A.many parseDigit <#> F.foldr (\d f → divNum (f + fromInt d) ten) zero
163172
exp ← parseExponent
164173
pure $ (lhs + rhs) * HN.pow ten exp
@@ -171,7 +180,6 @@ parsePositiveScientific = do
171180
HN.fromNumber $
172181
HN.toNumber a / HN.toNumber b
173182

174-
175183
parseHugeNum
176184
m
177185
. Monad m
@@ -202,8 +210,11 @@ parseBooleanLiteral =
202210
parseDecimalLiteral m. Monad m P.ParserT String m HN.HugeNum
203211
parseDecimalLiteral = parseHugeNum <|> parseScientific
204212

213+
parseHugeIntLiteral m. Monad m P.ParserT String m HI.HugeInt
214+
parseHugeIntLiteral = parseSigned (parseNat (HI.fromInt 10) HI.fromInt)
215+
205216
parseIntLiteral m. Monad m P.ParserT String m Int
206-
parseIntLiteral = parseSigned parseNat
217+
parseIntLiteral = parseSigned (parseNat 10 id)
207218

208219
parseStringLiteral m. Monad m P.ParserT String m String
209220
parseStringLiteral = quoted stringInner
@@ -226,11 +237,11 @@ parseEJsonF
226237
P.ParserT String m a
227238
P.ParserT String m (EJsonF a)
228239
parseEJsonF rec =
229-
PC.choice $
240+
PC.choice
230241
[ Null <$ parseNull
231242
, Boolean <$> parseBooleanLiteral
232243
, Decimal <$> PC.try parseDecimalLiteral
233-
, Integer <$> parseIntLiteral
244+
, Integer <$> parseHugeIntLiteral
234245
, String <$> parseStringLiteral
235246
, Array <$> parseArrayLiteral rec
236247
, Map <$> parseMapLiteral rec

src/Data/Json/Extended/Signature/Render.purs

+6-3
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,24 @@ import Prelude
66

77
import Data.Either (fromRight)
88
import Data.Foldable as F
9+
import Data.HugeInt as HI
910
import Data.HugeNum as HN
1011
import Data.Json.Extended.Signature.Core (EJsonF(..), EJsonMap(..))
12+
import Data.Maybe (fromMaybe)
13+
import Data.String as Str
1114
import Data.String.Regex as RX
1215
import Data.String.Regex.Flags as RXF
1316
import Data.Tuple as T
14-
1517
import Matryoshka (Algebra)
16-
1718
import Partial.Unsafe (unsafePartial)
1819

1920
renderEJsonF Algebra EJsonF String
2021
renderEJsonF = case _ of
2122
Null"null"
2223
Boolean b → if b then "true" else "false"
23-
Integer i → show i
24+
Integer i →
25+
let s = HN.toString (HI.toHugeNum i)
26+
in fromMaybe s $ Str.stripSuffix (Str.Pattern ".0") s
2427
Decimal a → HN.toString a
2528
String str → stringEJson str
2629
Array ds → squares $ commaSep ds

0 commit comments

Comments
 (0)