8 | module JSON.Simple.FromJSON
10 | import Data.List.Quantifiers as LQ
11 | import Data.Vect.Quantifiers as VQ
12 | import Data.SortedMap
13 | import Derive.Prelude
15 | import JSON.Simple.Option
16 | import JSON.Simple.ToJSON
19 | %language ElabReflection
28 | data JSONPathElement = Key String | Index Bits32
30 | %runElab derive "JSONPathElement" [Show,Eq]
34 | JSONPath = List JSONPathElement
38 | JSONErr = (JSONPath,String)
41 | Result : Type -> Type
42 | Result = Either JSONErr
45 | Parser : Type -> Type -> Type
46 | Parser v a = v -> Either JSONErr a
49 | orElse : Either a b -> Lazy (Either a b) -> Either a b
50 | orElse r@(Right _) _ = r
54 | (<|>) : Parser v a -> Parser v a -> Parser v a
55 | f <|> g = \vv => f vv `orElse` g vv
58 | data DecodingErr : Type where
59 | JErr : JSONErr -> DecodingErr
60 | JParseErr : ParseError Void -> DecodingErr
62 | %runElab derive "DecodingErr" [Show,Eq]
65 | DecodingResult : Type -> Type
66 | DecodingResult = Either DecodingErr
75 | formatRelativePath : JSONPath -> String
76 | formatRelativePath path = format "" path
78 | isIdentifierKey : List Char -> Bool
79 | isIdentifierKey [] = False
80 | isIdentifierKey (x::xs) = isAlpha x && all isAlphaNum xs
82 | escapeChar : Char -> String
83 | escapeChar '\'' = "\\'"
84 | escapeChar '\\' = "\\\\"
85 | escapeChar c = singleton c
87 | escapeKey : List Char -> String
88 | escapeKey = fastConcat . map escapeChar
90 | formatKey : String -> String
92 | let chars = fastUnpack key
93 | in if isIdentifierKey chars then fastPack $
'.' :: chars
94 | else "['" ++ escapeKey chars ++ "']"
96 | format : String -> JSONPath -> String
98 | format pfx (Index idx :: parts) = format (pfx ++ "[" ++ show idx ++ "]") parts
99 | format pfx (Key key :: parts) = format (pfx ++ formatKey key) parts
104 | formatPath : JSONPath -> String
105 | formatPath path = "$" ++ formatRelativePath path
110 | formatError : JSONPath -> String -> String
111 | formatError path msg = "Error in " ++ formatPath path ++ ": " ++ msg
114 | Interpolation DecodingErr where
115 | interpolate (JErr (p,s)) = formatError p s
116 | interpolate (JParseErr x) = interpolate x
123 | prettyErr : (input : String) -> DecodingErr -> String
124 | prettyErr _ = interpolate
131 | interface FromJSON a where
132 | constructor MkFromJSON
133 | fromJSON : Parser JSON a
136 | interface FromJSONKey a where
137 | constructor MkFromJSONKey
138 | fromKey : Parser String a
141 | decode : FromJSON a => String -> DecodingResult a
143 | let Right json := parseJSON Virtual s | Left err => Left (JParseErr err)
144 | Right res := fromJSON json | Left p => Left (JErr p)
148 | decodeEither : FromJSON a => String -> Either String a
149 | decodeEither s = mapFst interpolate $
decode s
152 | decodeMaybe : FromJSON a => String -> Maybe a
153 | decodeMaybe = either (const Nothing) Just . decode
160 | typeOf : JSON -> String
161 | typeOf JNull = "Null"
162 | typeOf (JBool _) = "Boolean"
163 | typeOf (JDouble _) = "Double"
164 | typeOf (JInteger _) = "Integer"
165 | typeOf (JString _) = "String"
166 | typeOf (JArray _) = "Array"
167 | typeOf (JObject _) = "Object"
170 | fail : String -> Result a
171 | fail s = Left (Nil,s)
173 | typeMismatch : String -> Parser JSON a
174 | typeMismatch expected actual =
175 | fail $
"expected \{expected}, but encountered \{typeOf actual}"
177 | unexpected : Parser JSON a
178 | unexpected actual = fail $
"unexpected \{typeOf actual}"
181 | modifyFailure : (String -> String) -> Result a -> Result a
182 | modifyFailure f = mapFst (map f)
187 | prependFailure : String -> Result a -> Result a
188 | prependFailure = modifyFailure . (++)
191 | prependContext : String -> Result a -> Result a
192 | prependContext name = prependFailure "parsing \{name} failed, "
195 | prependPath : Result a -> JSONPathElement -> Result a
196 | prependPath r elem = mapFst (\(path,s) => (elem :: path,s)) r
200 | -> (JSON -> Maybe t)
201 | -> (name : Lazy String)
204 | withValue s get n f val =
207 | Nothing => prependContext n $
typeMismatch s val
210 | withKey : Parser String a -> Parser String a
211 | withKey f = prependFailure "parsing key failed, " . f
214 | withObject : Lazy String -> Parser (List (String,JSON)) a -> Parser JSON a
215 | withObject = withValue "Object" $
\case JObject ps => Just ps;
_ => Nothing
218 | withBoolean : Lazy String -> Parser Bool a -> Parser JSON a
219 | withBoolean = withValue "Boolean" $
\case JBool b => Just b;
_ => Nothing
222 | withString : Lazy String -> Parser String a -> Parser JSON a
223 | withString = withValue "String" $
\case JString s => Just s;
_ => Nothing
226 | withNull : String -> t -> Parser JSON t
227 | withNull s x JNull = Right x
229 | prependContext s $
fail "expexted Null but encountered \{typeOf v}"
232 | eqString : Lazy String -> String -> Parser JSON ()
233 | eqString n s = withString n $
\s' =>
234 | if s == s' then Right () else fail "expected '\{s}' but got '\{s'}'"
237 | withDouble : Lazy String -> Parser Double a -> Parser JSON a
239 | withValue "Double" $
\case
240 | JDouble d => Just d
241 | JInteger n => Just (cast n)
245 | withInteger : Lazy String -> Parser Integer a -> Parser JSON a
246 | withInteger = withValue "Integer" $
\case JInteger d => Just d;
_ => Nothing
249 | pint1 : PVal1 q Void Integer
250 | pint1 = value Nothing [(decimal, bytes decimal)]
253 | withIntegerKey : Parser Integer a -> Parser String a
256 | case parseString pint1 Virtual s of
258 | Left _ => fail "not an integer: \{s}"
264 | -> (lower : Integer)
265 | -> (upper : Integer)
267 | boundedIntegral s lo up =
268 | withInteger s $
\n =>
269 | if n >= lo && n <= up
270 | then Right $
fromInteger n
271 | else fail "integer out of bounds: \{show n}"
274 | boundedIntegralKey :
276 | -> (lower : Integer)
277 | -> (upper : Integer)
279 | boundedIntegralKey lo up =
280 | withIntegerKey $
\n =>
281 | if n >= lo && n <= up
282 | then Right $
fromInteger n
283 | else fail "integer out of bounds: \{show n}"
286 | withArray : Lazy String -> Parser (List JSON) a -> Parser JSON a
287 | withArray = withValue "Array" $
\case JArray v => Just v;
_ => Nothing
293 | -> Parser (Vect n JSON) a
295 | withArrayN n = withValue "Array of length \{show n}" $
296 | \case JArray v => toVect n v;
_ => Nothing
300 | explicitParseField : Parser JSON a -> List (String,JSON) -> Parser String a
301 | explicitParseField p o key =
302 | case lookup key o of
303 | Nothing => fail "key \{show key} not found"
304 | Just v => p v `prependPath` Key key
308 | explicitParseFieldMaybe :
310 | -> List (String,JSON)
311 | -> Parser String (Maybe a)
312 | explicitParseFieldMaybe p o key =
313 | case lookup key o of
314 | Nothing => Right Nothing
315 | Just JNull => Right Nothing
316 | Just v => map Just $
p v `prependPath` Key key
320 | explicitParseFieldMaybe' :
322 | -> List (String,JSON)
324 | explicitParseFieldMaybe' p o key =
325 | case lookup key o of
326 | Nothing => p JNull `prependPath` Key key
327 | Just v => p v `prependPath` Key key
337 | field : FromJSON a => List (String,JSON) -> Parser String a
338 | field = explicitParseField fromJSON
348 | fieldMaybe : FromJSON a => List (String,JSON) -> Parser String (Maybe a)
349 | fieldMaybe = explicitParseFieldMaybe fromJSON
357 | optField : FromJSON a => List (String,JSON) -> Parser String a
358 | optField = explicitParseFieldMaybe' fromJSON
363 | fieldWithDeflt : FromJSON a => List (String,JSON) -> Lazy a -> Parser String a
364 | fieldWithDeflt ps v s = fromMaybe v <$> fieldMaybe ps s
371 | FromJSON JSON where fromJSON = Right
374 | FromJSON Void where
375 | fromJSON v = fail "Cannot parse Void"
379 | fromJSON = withArray "()" $
380 | \case Nil => Right ()
381 | _ :: _ => fail "parsing () failed, expected empty list"
384 | FromJSON Bool where
385 | fromJSON = withBoolean "Bool" Right
388 | FromJSONKey Bool where
391 | \case "True" => Right True
392 | "False" => Right False
393 | s => fail "not a bool: \{s}"
396 | FromJSON Double where
397 | fromJSON = withDouble "Double" Right
400 | pdbl1 : PVal1 q Void Double
401 | pdbl1 = value Nothing [(jsonDouble, txt jdouble)]
404 | FromJSONKey Double where
407 | case parseString pdbl1 Virtual s of
409 | Left _ => fail "not a floating point number: \{s}"
412 | FromJSON Bits8 where
413 | fromJSON = boundedIntegral "Bits8" 0 0xff
416 | FromJSON Bits16 where
417 | fromJSON = boundedIntegral "Bits16" 0 0xffff
420 | FromJSON Bits32 where
421 | fromJSON = boundedIntegral "Bits32" 0 0xffffffff
424 | FromJSON Bits64 where
425 | fromJSON = boundedIntegral "Bits64" 0 0xffffffffffffffff
429 | fromJSON = boundedIntegral "Int" (-
0x8000000000000000) 0x7fffffffffffffff
432 | FromJSON Int8 where
433 | fromJSON = boundedIntegral "Int8" (-
0x80) 0x7f
436 | FromJSON Int16 where
437 | fromJSON = boundedIntegral "Int16" (-
0x8000) 0x7fff
440 | FromJSON Int32 where
441 | fromJSON = boundedIntegral "Int32" (-
0x80000000) 0x7fffffff
444 | FromJSON Int64 where
445 | fromJSON = boundedIntegral "Int64" (-
0x8000000000000000) 0x7fffffffffffffff
448 | FromJSONKey Bits8 where
449 | fromKey = boundedIntegralKey 0 0xff
452 | FromJSONKey Bits16 where
453 | fromKey = boundedIntegralKey 0 0xffff
456 | FromJSONKey Bits32 where
457 | fromKey = boundedIntegralKey 0 0xffffffff
460 | FromJSONKey Bits64 where
461 | fromKey = boundedIntegralKey 0 0xffffffffffffffff
464 | FromJSONKey Int where
465 | fromKey = boundedIntegralKey (-
0x8000000000000000) 0x7fffffffffffffff
468 | FromJSONKey Int8 where
469 | fromKey = boundedIntegralKey (-
0x80) 0x7f
472 | FromJSONKey Int16 where
473 | fromKey = boundedIntegralKey (-
0x8000) 0x7fff
476 | FromJSONKey Int32 where
477 | fromKey = boundedIntegralKey (-
0x80000000) 0x7fffffff
480 | FromJSONKey Int64 where
481 | fromKey = boundedIntegralKey (-
0x8000000000000000) 0x7fffffffffffffff
485 | fromJSON = withInteger "Nat" $
\n =>
486 | if n >= 0 then Right $
fromInteger n
487 | else fail "not a natural number: \{show n}"
490 | FromJSONKey Nat where
491 | fromKey = withIntegerKey $
\n =>
492 | if n >= 0 then Right $
fromInteger n
493 | else fail "not a natural number: \{show n}"
496 | FromJSON Integer where
497 | fromJSON = withInteger "Integer" Right
500 | FromJSONKey Integer where
501 | fromKey = withIntegerKey Right
504 | FromJSON String where
505 | fromJSON = withString "String" Right
508 | FromJSONKey String where
509 | fromKey = withKey Right
512 | FromJSON Char where
513 | fromJSON = withString "Char" $
\str =>
515 | StrCons c "" => Right c
516 | _ => fail "expected a string of length 1"
519 | FromJSONKey Char where
520 | fromKey = withKey $
\str =>
522 | StrCons c "" => Right c
523 | _ => fail "expected a string of length 1"
526 | FromJSON a => FromJSON (Maybe a) where
527 | fromJSON JNull = Right Nothing
528 | fromJSON v = Just <$> fromJSON v
531 | FromJSON a => FromJSON (List a) where
532 | fromJSON = withArray "List" $
traverse fromJSON
535 | FromJSON a => FromJSON (SnocList a) where
536 | fromJSON = map ([<] <><) . fromJSON
539 | FromJSON a => FromJSON (List1 a) where
540 | fromJSON = withArray "List1" $
\case
541 | Nil => fail "expected non-empty list"
542 | h :: t => traverse fromJSON (h ::: t)
546 | -> {auto jk : FromJSONKey k}
547 | -> {auto jv : FromJSON v}
549 | -> Parser (List (String,JSON)) (SortedMap k v)
550 | sortedMap m [] = Right m
551 | sortedMap m ((x,y) :: ps) =
552 | let Right k' := fromKey x | Left err => Left err
553 | Right v' := fromJSON y | Left err => Left err
554 | in sortedMap (insert k' v' m) ps
557 | Ord k => FromJSONKey k => FromJSON v => FromJSON (SortedMap k v) where
558 | fromJSON = withObject "SortedMap" (sortedMap empty)
561 | {n : Nat} -> FromJSON a => FromJSON (Vect n a) where
562 | fromJSON = withArray "Vect \{show n}" $
\vs => case toVect n vs of
563 | Just vect => traverse fromJSON vect
564 | Nothing => fail "expected list of length \{show n}"
567 | FromJSON a => FromJSON b => FromJSON (Either a b) where
568 | fromJSON = withObject "Either" $
\o =>
569 | map Left (field o "Left") `orElse`
570 | map Right (field o "Right")
573 | FromJSON a => FromJSON b => FromJSON (a, b) where
574 | fromJSON = withArray "Pair" $
575 | \case [x,y] => [| MkPair (fromJSON x) (fromJSON y) |]
576 | _ => fail "expected a pair of values"
578 | readLQ : (ps : LQ.All.All (FromJSON . f) ts) => Parser (List JSON) (All f ts)
579 | readLQ @{[]} [] = Right []
580 | readLQ @{_::_} (x :: xs) = [| fromJSON x :: readLQ xs |]
581 | readLQ @{_::_} [] = fail "list of values too short"
582 | readLQ @{[]} _ = fail "list of values too long"
584 | readVQ : (ps : VQ.All.All (FromJSON . f) ts) => Parser (List JSON) (All f ts)
585 | readVQ @{[]} [] = Right []
586 | readVQ @{_::_} (x :: xs) = [| fromJSON x :: readVQ xs |]
587 | readVQ @{_::_} [] = fail "list of values too short"
588 | readVQ @{[]} _ = fail "list of values too long"
591 | LQ.All.All (FromJSON . f) ts => FromJSON (All f ts) where
592 | fromJSON = withArray "HList" $
readLQ
595 | VQ.All.All (FromJSON . f) ts => FromJSON (VQ.All.All f ts) where
596 | fromJSON = withArray "HVect" $
readVQ
604 | (tpe : Lazy String)
605 | -> Parser (String,JSON) a
607 | fromSingleField n f = withObject n $
609 | _ => fail "expected single field object"
618 | (tpe : Lazy String)
619 | -> Parser (String,JSON) a
621 | fromTwoElemArray n f =
622 | withArrayN 2 n $
\[x,y] => withString n (\s => f (s,y)) x
631 | (tpe : Lazy String)
632 | -> (tagField, contentField : String)
633 | -> Parser (String,JSON) a
635 | fromTaggedObject n tf cf f = withObject n $
\o => do
637 | v <- explicitParseField Right o cf