1{-# OPTIONS_GHC -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing #-}
2{-# LANGUAGE BangPatterns, Rank2Types, OverloadedStrings, UnboxedTuples #-}
25 , DecodeExpectation(..)
32import qualified Data.ByteString.Internal as B
33import qualified Data.Map as Map
34import qualified Data.NonEmptyList as NE
35import Data.Word (Word8, Word16)
36import Foreign.Ptr (Ptr, plusPtr, minusPtr)
37import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
39import qualified Json.String as Json
40import qualified Parse.Keyword as K
41import qualified Parse.Primitives as P
42import Parse.Primitives (Row, Col)
43import qualified Reporting.Annotation as A
50fromByteString :: Decoder x a -> B.ByteString -> Either (Error x) a
51fromByteString (Decoder decode) src =
52 case P.fromByteString pFile BadEnd src of
54 decode ast Right (Left . DecodeProblem src)
57 Left (ParseProblem src problem)
80 = DecodeProblem B.ByteString (Problem x)
81 | ParseProblem B.ByteString ParseError
89 = Field B.ByteString (Problem x)
90 | Index Int (Problem x)
91 | OneOf (Problem x) [Problem x]
93 | Expecting A.Region DecodeExpectation
102 | TObjectWith B.ByteString
110instance Functor (Decoder x) where
112 fmap func (Decoder decodeA) =
113 Decoder $ \ast ok err ->
120instance Applicative (Decoder x) where
125 (<*>) (Decoder decodeFunc) (Decoder decodeArg) =
126 Decoder $ \ast ok err ->
130 okA arg = ok (func arg)
132 decodeArg ast okA err
134 decodeFunc ast okF err
137instance Monad (Decoder x) where
138 {-# INLINE return #-}
144 (>>=) (Decoder decodeA) callback =
145 Decoder $ \ast ok err ->
149 Decoder decodeB -> decodeB ast ok err
158string :: Decoder x Json.String
160 Decoder $ \(A.At region ast) ok err ->
163 ok (Json.fromSnippet snippet)
166 err (Expecting region TString)
169customString :: P.Parser x a -> (Row -> Col -> x) -> Decoder x a
170customString parser toBadEnd =
171 Decoder $ \(A.At region ast) ok err ->
174 case P.fromSnippet parser toBadEnd snippet of
176 Left x -> err (Failure region x)
179 err (Expecting region TString)
186bool :: Decoder x Bool
188 Decoder $ \(A.At region ast) ok err ->
197 err (Expecting region TBool)
206 Decoder $ \(A.At region ast) ok err ->
212 err (Expecting region TInt)
219list :: Decoder x a -> Decoder x [a]
221 Decoder $ \(A.At region ast) ok err ->
224 listHelp decoder ok err 0 asts []
227 err (Expecting region TArray)
230listHelp :: Decoder x a -> ([a] -> b) -> (Problem x -> b) -> Int -> [AST] -> [a] -> b
231listHelp decoder@(Decoder decodeA) ok err !i asts revs =
238 ok' value = listHelp decoder ok err (i+1) asts (value:revs)
239 err' prob = err (Index i prob)
248nonEmptyList :: Decoder x a -> x -> Decoder x (NE.List a)
249nonEmptyList decoder x =
250 do values <- list decoder
252 v:vs -> return (NE.List v vs)
260pair :: Decoder x a -> Decoder x b -> Decoder x (a,b)
261pair (Decoder decodeA) (Decoder decodeB) =
262 Decoder $ \(A.At region ast) ok err ->
268 err0 e = err (Index 0 e)
271 err1 e = err (Index 1 e)
274 decodeB astB ok1 err1
276 decodeA astA ok0 err0
279 err (Expecting region (TArrayPair (length vs)))
282 err (Expecting region TArray)
290 KeyDecoder (P.Parser x a) (Row -> Col -> x)
293dict :: (Ord k) => KeyDecoder x k -> Decoder x a -> Decoder x (Map.Map k a)
294dict keyDecoder valueDecoder =
295 Map.fromList <$> pairs keyDecoder valueDecoder
298pairs :: KeyDecoder x k -> Decoder x a -> Decoder x [(k, a)]
299pairs keyDecoder valueDecoder =
300 Decoder $ \(A.At region ast) ok err ->
303 pairsHelp keyDecoder valueDecoder ok err kvs []
306 err (Expecting region TObject)
309pairsHelp :: KeyDecoder x k -> Decoder x a -> ([(k, a)] -> b) -> (Problem x -> b) -> [(P.Snippet, AST)] -> [(k, a)] -> b
310pairsHelp keyDecoder@(KeyDecoder keyParser toBadEnd) valueDecoder@(Decoder decodeA) ok err kvs revs =
315 (snippet, ast) : kvs ->
316 case P.fromSnippet keyParser toBadEnd snippet of
318 err (Failure (snippetToRegion snippet) x)
322 ok' value = pairsHelp keyDecoder valueDecoder ok err kvs ((key,value):revs)
324 let (P.Snippet fptr off len _ _) = snippet in
325 err (Field (B.PS fptr off len) prob)
330snippetToRegion :: P.Snippet -> A.Region
331snippetToRegion (P.Snippet _ _ len row col) =
332 A.Region (A.Position row col) (A.Position row (col + fromIntegral len))
339field :: B.ByteString -> Decoder x a -> Decoder x a
340field key (Decoder decodeA) =
341 Decoder $ \(A.At region ast) ok err ->
344 case findField key kvs of
350 decodeA value ok err'
353 err (Expecting region (TObjectWith key))
356 err (Expecting region TObject)
359findField :: B.ByteString -> [(P.Snippet, AST)] -> Maybe AST
365 (P.Snippet fptr off len _ _, value) : remainingPairs ->
366 if key == B.PS fptr off len
368 else findField key remainingPairs
375oneOf :: [Decoder x a] -> Decoder x a
377 Decoder $ \ast ok err ->
379 Decoder decodeA : decoders ->
382 oneOfHelp ast ok err decoders e []
387 error "Ran into (Json.Decode.oneOf [])"
390oneOfHelp :: AST -> (a -> b) -> (Problem x -> b) -> [Decoder x a] -> Problem x -> [Problem x] -> b
391oneOfHelp ast ok err decoders p ps =
393 Decoder decodeA : decoders ->
396 oneOfHelp ast ok err decoders p' (p:ps)
401 err (oneOfError [] p ps)
404oneOfError :: [Problem x] -> Problem x -> [Problem x] -> Problem x
405oneOfError problems prob ps =
411 oneOfError (prob:problems) p ps
418failure :: x -> Decoder x a
420 Decoder $ \(A.At region _) _ err ->
421 err (Failure region x)
428mapError :: (x -> y) -> Decoder x a -> Decoder y a
429mapError func (Decoder decodeA) =
430 Decoder $ \ast ok err ->
432 err' prob = err (mapErrorHelp func prob)
437mapErrorHelp :: (x -> y) -> Problem x -> Problem y
438mapErrorHelp func problem =
440 Field k p -> Field k (mapErrorHelp func p)
441 Index i p -> Index i (mapErrorHelp func p)
442 OneOf p ps -> OneOf (mapErrorHelp func p) (map (mapErrorHelp func) ps)
443 Failure r x -> Failure r (func x)
444 Expecting r e -> Expecting r e
457 | Object [(P.Snippet, AST)]
470 P.Parser ParseError a
475 | ObjectField Row Col
476 | ObjectColon Row Col
479 | StringProblem StringProblem Row Col
480 | NoLeadingZeros Row Col
484-- PIndex Int ParseError Row Col
485-- PField Json.String ParseError Row Col
490 | BadStringControlChar
491 | BadStringEscapeChar
511 [ String <$> pString Start
515 , K.k4 0x74 0x72 0x75 0x65 Start >> return TRUE
516 , K.k5 0x66 0x61 0x6C 0x73 0x65 Start >> return FALSE
517 , K.k4 0x6E 0x75 0x6C 0x6C Start >> return NULL
525pObject :: Parser AST_
527 do P.word1 0x7B {- { -} Start
533 , do P.word1 0x7D {-}-} ObjectEnd
538pObjectHelp :: [(P.Snippet, AST)] -> Parser AST_
539pObjectHelp revEntries =
542 do P.word1 0x2C {-,-} ObjectEnd
546 pObjectHelp (entry:revEntries)
548 do P.word1 0x7D {-}-} ObjectEnd
549 return (Object (reverse revEntries))
553pField :: Parser (P.Snippet, AST)
555 do key <- pString ObjectField
557 P.word1 0x3A {-:-} ObjectColon
569 do P.word1 0x5B {-[-} Start
575 , do P.word1 0x5D {-]-} ArrayEnd
580pArrayHelp :: Int -> [AST] -> Parser AST_
581pArrayHelp !len revEntries =
584 do P.word1 0x2C {-,-} ArrayEnd
588 pArrayHelp (len + 1) (entry:revEntries)
590 do P.word1 0x5D {-]-} ArrayEnd
591 return (Array (reverse revEntries))
599pString :: (Row -> Col -> ParseError) -> Parser P.Snippet
601 P.Parser $ \(P.State src pos end indent row col) cok _ cerr eerr ->
602 if pos < end && P.unsafeIndex pos == 0x22 {-"-} then
605 !pos1 = plusPtr pos 1
608 (# status, newPos, newRow, newCol #) =
609 pStringHelp pos1 end row col1
614 !off = minusPtr pos1 (unsafeForeignPtrToPtr src)
615 !len = minusPtr newPos pos1 - 1
616 !snp = P.Snippet src off len row col1
617 !newState = P.State src newPos end indent newRow newCol
622 cerr newRow newCol (StringProblem problem)
630 | BadString StringProblem
633pStringHelp :: Ptr Word8 -> Ptr Word8 -> Word16 -> Word16 -> (# StringStatus, Ptr Word8, Word16, Word16 #)
634pStringHelp pos end row col =
636 (# BadString BadStringEnd, pos, row, col #)
639 case P.unsafeIndex pos of
641 (# GoodString, plusPtr pos 1, row, col + 1 #)
644 (# BadString BadStringEnd, pos, row, col #)
647 let !pos1 = plusPtr pos 1 in
649 (# BadString BadStringEnd, pos1, row + 1, col #)
651 case P.unsafeIndex pos1 of
652 0x22 {-"-} -> pStringHelp (plusPtr pos 2) end row (col + 2)
653 0x5C {-\-} -> pStringHelp (plusPtr pos 2) end row (col + 2)
654 0x2F {-/-} -> pStringHelp (plusPtr pos 2) end row (col + 2)
655 0x62 {-b-} -> pStringHelp (plusPtr pos 2) end row (col + 2)
656 0x66 {-f-} -> pStringHelp (plusPtr pos 2) end row (col + 2)
657 0x6E {-n-} -> pStringHelp (plusPtr pos 2) end row (col + 2)
658 0x72 {-r-} -> pStringHelp (plusPtr pos 2) end row (col + 2)
659 0x74 {-t-} -> pStringHelp (plusPtr pos 2) end row (col + 2)
661 let !pos6 = plusPtr pos 6 in
663 && isHex (P.unsafeIndex (plusPtr pos 2))
664 && isHex (P.unsafeIndex (plusPtr pos 3))
665 && isHex (P.unsafeIndex (plusPtr pos 4))
666 && isHex (P.unsafeIndex (plusPtr pos 5))
668 pStringHelp pos6 end row (col + 6)
670 (# BadString BadStringEscapeHex, pos, row, col #)
673 (# BadString BadStringEscapeChar, pos, row, col #)
677 (# BadString BadStringControlChar, pos, row, col #)
679 let !newPos = plusPtr pos (P.getCharWidth word) in
680 pStringHelp newPos end row (col + 1)
683isHex :: Word8 -> Bool
685 0x30 {-0-} <= word && word <= 0x39 {-9-}
686 || 0x61 {-a-} <= word && word <= 0x66 {-f-}
687 || 0x41 {-A-} <= word && word <= 0x46 {-F-}
696 P.Parser $ \state@(P.State src pos end indent row col) cok eok _ _ ->
698 (# newPos, newRow, newCol #) =
699 eatSpaces pos end row col
701 if pos == newPos then
706 P.State src newPos end indent newRow newCol
711eatSpaces :: Ptr Word8 -> Ptr Word8 -> Word16 -> Word16 -> (# Ptr Word8, Word16, Word16 #)
712eatSpaces pos end row col =
717 case P.unsafeIndex pos of
718 0x20 {- -} -> eatSpaces (plusPtr pos 1) end row (col + 1)
719 0x09 {-\t-} -> eatSpaces (plusPtr pos 1) end row (col + 1)
720 0x0A {-\n-} -> eatSpaces (plusPtr pos 1) end (row + 1) 1
721 0x0D {-\r-} -> eatSpaces (plusPtr pos 1) end row col
732 P.Parser $ \(P.State src pos end indent row col) cok _ cerr eerr ->
737 let !word = P.unsafeIndex pos in
738 if not (isDecimalDigit word) then
741 else if word == 0x30 {-0-} then
744 !pos1 = plusPtr pos 1
745 !newState = P.State src pos1 end indent row (col + 1)
748 let !word1 = P.unsafeIndex pos1 in
749 if isDecimalDigit word1 then
750 cerr row (col + 1) NoLeadingZeros
751 else if word1 == 0x2E {-.-} then
752 cerr row (col + 1) NoFloats
760 (# status, n, newPos #) =
761 chompInt (plusPtr pos 1) end (fromIntegral (word - 0x30 {-0-}))
763 !len = fromIntegral (minusPtr newPos pos)
769 P.State src newPos end indent row (col + len)
774 cerr row (col + len) NoFloats
777data IntStatus = GoodInt | BadIntEnd
780chompInt :: Ptr Word8 -> Ptr Word8 -> Int -> (# IntStatus, Int, Ptr Word8 #)
783 let !word = P.unsafeIndex pos in
784 if isDecimalDigit word then
785 let !m = 10 * n + fromIntegral (word - 0x30 {-0-}) in
786 chompInt (plusPtr pos 1) end m
787 else if word == 0x2E {-.-} || word == 0x65 {-e-} || word == 0x45 {-E-} then
788 (# BadIntEnd, n, pos #)
790 (# GoodInt, n, pos #)
793 (# GoodInt, n, pos #)
796{-# INLINE isDecimalDigit #-}
797isDecimalDigit :: Word8 -> Bool
799 word <= 0x39 {-9-} && word >= 0x30 {-0-}
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list