crypton-asn1-parse 0.9.5 → 0.9.6
raw patch · 5 files changed
+244/−208 lines, 5 filesdep −crypton-asn1-encodingdep ~basedep ~crypton-asn1-typesPVP ok
version bump matches the API change (PVP)
Dependencies removed: crypton-asn1-encoding
Dependency ranges changed: base, crypton-asn1-types
API changes (from Hackage documentation)
Files
- CHANGELOG.md +10/−0
- Data/ASN1/Parse.hs +0/−164
- README.md +2/−3
- crypton-asn1-parse.cabal +46/−41
- src/Data/ASN1/Parse.hs +186/−0
CHANGELOG.md view
@@ -6,6 +6,16 @@ and this project adheres to the [Haskell Package Versioning Policy](https://pvp.haskell.org/). +## 0.9.6 + +* Move library modules to directory `src`. +* Drop support for GHC < 8.8. +* Depend on `crypton-asn1-types >= 0.3.6` and drop dependency on + `crypton-asn1-encoding`. +* Re-exports module `Data.Types.ASN1` from package `crypton-asn1-types`. +* Use `other-extensions` field in Cabal file. +* Cabal file specifies `cabal-version: 1.22` (not `1.18`). + ## 0.9.5 * Rename `asn1-parse-0.9.5` package as `crypton-asn1-parse-0.9.5`.
− Data/ASN1/Parse.hs
@@ -1,164 +0,0 @@--- | --- Module : Data.ASN1.Parse --- License : BSD-style --- Maintainer : Vincent Hanquez <vincent@snarc.org> --- Stability : experimental --- Portability : unknown --- --- A parser combinator for ASN1 Stream. -{-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE CPP #-} -module Data.ASN1.Parse - ( ParseASN1 - -- * run - , runParseASN1State - , runParseASN1 - , throwParseError - -- * combinators - , onNextContainer - , onNextContainerMaybe - , getNextContainer - , getNextContainerMaybe - , getNext - , getNextMaybe - , hasNext - , getObject - , getMany - ) where - -import Data.ASN1.Types -import Data.ASN1.Stream -import Control.Applicative -import Control.Arrow (first) -import Control.Monad (liftM2) -#if MIN_VERSION_base(4,9,0) -import Control.Monad.Fail -#endif - -newtype ParseASN1 a = P { runP :: [ASN1] -> Either String (a, [ASN1]) } - -instance Functor ParseASN1 where - fmap f m = P (either Left (Right . first f) . runP m) -instance Applicative ParseASN1 where - pure a = P $ \s -> Right (a, s) - (<*>) mf ma = P $ \s -> - case runP mf s of - Left err -> Left err - Right (f, s2) -> - case runP ma s2 of - Left err -> Left err - Right (a, s3) -> Right (f a, s3) -instance Monad ParseASN1 where - return a = pure a - (>>=) m1 m2 = P $ \s -> - case runP m1 s of - Left err -> Left err - Right (a, s2) -> runP (m2 a) s2 -instance Alternative ParseASN1 where - empty = P $ \_ -> Left "empty Alternative" - (<|>) m1 m2 = P $ \s -> - case runP m1 s of - Left _ -> runP m2 s - Right (a, s2) -> Right (a, s2) -#if MIN_VERSION_base(4,9,0) -instance MonadFail ParseASN1 where - fail = throwParseError -#endif - -get :: ParseASN1 [ASN1] -get = P $ \stream -> Right (stream, stream) - -put :: [ASN1] -> ParseASN1 () -put stream = P $ \_ -> Right ((), stream) - --- | throw a parse error -throwParseError :: String -> ParseASN1 a -throwParseError s = P $ \_ -> Left s - --- | run the parse monad over a stream and returns the result and the remaining ASN1 Stream. -runParseASN1State :: ParseASN1 a -> [ASN1] -> Either String (a,[ASN1]) -runParseASN1State f s = runP f s - --- | run the parse monad over a stream and returns the result. --- --- If there's still some asn1 object in the state after calling f, --- an error will be raised. -runParseASN1 :: ParseASN1 a -> [ASN1] -> Either String a -runParseASN1 f s = - case runP f s of - Left err -> Left err - Right (o, []) -> Right o - Right (_, er) -> Left ("runParseASN1: remaining state " ++ show er) - --- | get next object -getObject :: ASN1Object a => ParseASN1 a -getObject = do - l <- get - case fromASN1 l of - Left err -> throwParseError err - Right (a,l2) -> put l2 >> return a - --- | get next element from the stream -getNext :: ParseASN1 ASN1 -getNext = do - list <- get - case list of - [] -> throwParseError "empty" - (h:l) -> put l >> return h - --- | get many elements until there's nothing left -getMany :: ParseASN1 a -> ParseASN1 [a] -getMany getOne = do - next <- hasNext - if next - then liftM2 (:) getOne (getMany getOne) - else return [] - --- | get next element from the stream maybe -getNextMaybe :: (ASN1 -> Maybe a) -> ParseASN1 (Maybe a) -getNextMaybe f = do - list <- get - case list of - [] -> return Nothing - (h:l) -> let r = f h - in do case r of - Nothing -> put list - Just _ -> put l - return r - --- | get next container of specified type and return all its elements -getNextContainer :: ASN1ConstructionType -> ParseASN1 [ASN1] -getNextContainer ty = do - list <- get - case list of - [] -> throwParseError "empty" - (h:l) | h == Start ty -> do let (l1, l2) = getConstructedEnd 0 l - put l2 >> return l1 - | otherwise -> throwParseError "not an expected container" - - --- | run a function of the next elements of a container of specified type -onNextContainer :: ASN1ConstructionType -> ParseASN1 a -> ParseASN1 a -onNextContainer ty f = getNextContainer ty >>= either throwParseError return . runParseASN1 f - --- | just like getNextContainer, except it doesn't throw an error if the container doesn't exists. -getNextContainerMaybe :: ASN1ConstructionType -> ParseASN1 (Maybe [ASN1]) -getNextContainerMaybe ty = do - list <- get - case list of - [] -> return Nothing - (h:l) | h == Start ty -> do let (l1, l2) = getConstructedEnd 0 l - put l2 >> return (Just l1) - | otherwise -> return Nothing - --- | just like onNextContainer, except it doesn't throw an error if the container doesn't exists. -onNextContainerMaybe :: ASN1ConstructionType -> ParseASN1 a -> ParseASN1 (Maybe a) -onNextContainerMaybe ty f = do - n <- getNextContainerMaybe ty - case n of - Just l -> either throwParseError (return . Just) $ runParseASN1 f l - Nothing -> return Nothing - --- | returns if there's more elements in the stream. -hasNext :: ParseASN1 Bool -hasNext = not . null <$> get
README.md view
@@ -4,9 +4,8 @@ Originally forked from [asn1-parse-0.9.5](https://hackage.haskell.org/package/asn1-parse-0.9.5). -ASN.1 for Haskell - -* crypton-asn1-parse : combinator based parsers for ASN.1 types. +A library providing a monadic parser combinator for use with a stream of +Abstract Syntax Notation One (ASN.1) standard values. History -------
crypton-asn1-parse.cabal view
@@ -1,41 +1,46 @@-cabal-version: 1.18 - --- This file has been generated from package.yaml by hpack version 0.38.1. --- --- see: https://github.com/sol/hpack - -name: crypton-asn1-parse -version: 0.9.5 -synopsis: Simple monadic parser for ASN1 stream types. -description: Simple monadic parser for ASN1 stream types, when ASN1 pattern matching is not - convenient. -category: Data -stability: experimental -homepage: https://github.com/mpilgrem/crypton-asn1 -bug-reports: https://github.com/mpilgrem/crypton-asn1/issues -author: Vincent Hanquez <vincent@snarc.org> -maintainer: Mike Pilgrem <public@pilgrem.com>, - Kazu Yamamoto <kazu@iij.ad.jp> -copyright: Vincent Hanquez <vincent@snarc.org> -license: BSD3 -license-file: LICENSE -build-type: Simple -extra-doc-files: - CHANGELOG.md - README.md - -source-repository head - type: git - location: https://github.com/mpilgrem/crypton-asn1 - subdir: parse - -library - exposed-modules: - Data.ASN1.Parse - ghc-options: -Wall - build-depends: - base >=3 && <5 - , bytestring - , crypton-asn1-encoding >=0.9 - , crypton-asn1-types ==0.3.* - default-language: Haskell98 +cabal-version: 1.22 ++-- This file has been generated from package.yaml by hpack version 0.38.1.+--+-- see: https://github.com/sol/hpack++name: crypton-asn1-parse+version: 0.9.6+synopsis: A monadic parser combinator for a ASN.1 stream.+description: A library providing a monadic parser combinator for use with a stream of+ Abstract Syntax Notation One (ASN.1) standard values.+category: Data+stability: experimental+homepage: https://github.com/mpilgrem/crypton-asn1+bug-reports: https://github.com/mpilgrem/crypton-asn1/issues+author: Vincent Hanquez <vincent@snarc.org>+maintainer: Mike Pilgrem <public@pilgrem.com>,+ Kazu Yamamoto <kazu@iij.ad.jp>+copyright: Vincent Hanquez <vincent@snarc.org>+license: BSD3+license-file: LICENSE+build-type: Simple+extra-doc-files:+ CHANGELOG.md+ README.md++source-repository head+ type: git+ location: https://github.com/mpilgrem/crypton-asn1+ subdir: parse++library+ exposed-modules:+ Data.ASN1.Parse+ reexported-modules:+ Data.ASN1.Types+ hs-source-dirs:+ src+ other-extensions:+ LambdaCase+ ghc-options: -Wall+ build-depends:+ base >=4.13 && <5+ , bytestring+ , crypton-asn1-types >=0.3.6 && <0.4+ default-language: Haskell98
+ src/Data/ASN1/Parse.hs view
@@ -0,0 +1,186 @@+{-# LANGUAGE LambdaCase #-} + +{- | +Module : Data.ASN1.Parse +License : BSD-style +Copyright : (c) 2010-2013 Vincent Hanquez <vincent@snarc.org> +Stability : experimental +Portability : unknown + +A monadic parser combinator for a stream of ASN.1 items. +-} + +module Data.ASN1.Parse + ( ParseASN1 + -- * Run 'ParseASN1' + , runParseASN1State + , runParseASN1 + , throwParseError + -- * Combinators + , onNextContainer + , onNextContainerMaybe + , getNextContainer + , getNextContainerMaybe + , getNext + , getNextMaybe + , hasNext + , getObject + , getMany + ) where + +import Control.Applicative ( Alternative (..) ) +import Control.Arrow ( first ) +import Control.Monad ( liftM2 ) +import Data.ASN1.Types + ( ASN1 (..), ASN1ConstructionType (..), ASN1Object (..) ) +import Data.ASN1.Stream ( getConstructedEnd ) + +-- | Type representing a parser combinator for a stream of ASN.1 items. +newtype ParseASN1 a = P { runP :: [ASN1] -> Either String (a, [ASN1]) } + +instance Functor ParseASN1 where + fmap f m = P (fmap (first f) . runP m) + +instance Applicative ParseASN1 where + pure a = P $ \s -> Right (a, s) + + (<*>) mf ma = P $ \s -> + case runP mf s of + Left err -> Left err + Right (f, s2) -> + case runP ma s2 of + Left err -> Left err + Right (a, s3) -> Right (f a, s3) + +instance Monad ParseASN1 where + return = pure + + (>>=) m1 m2 = P $ \s -> + case runP m1 s of + Left err -> Left err + Right (a, s2) -> runP (m2 a) s2 + +instance Alternative ParseASN1 where + empty = P $ \_ -> Left "empty Alternative" + + (<|>) m1 m2 = P $ \s -> + case runP m1 s of + Left _ -> runP m2 s + Right (a, s2) -> Right (a, s2) + +instance MonadFail ParseASN1 where + fail = throwParseError + +-- | Run the given parse monad over the given list of ASN.1 items. Returns the +-- result and a list of the ASN.1 items remaining in the stream (if successful). +runParseASN1State :: ParseASN1 a -> [ASN1] -> Either String (a, [ASN1]) +runParseASN1State = runP + +-- | Run the given parse monad over the given list of ASN.1 items and returns +-- the result (if successful). +-- +-- If ASN.1 items remain in the stream after doing so, returns an error. +runParseASN1 :: ParseASN1 a -> [ASN1] -> Either String a +runParseASN1 f list = + case runP f list of + Left err -> Left err + Right (result, []) -> Right result + Right (_, rest) -> Left ("runParseASN1: remaining state " ++ show rest) + +-- | Throw a parse error. +throwParseError :: + String + -- ^ Error message. + -> ParseASN1 a +throwParseError err = P $ \_ -> Left err + +-- | Returns a list of ASN.1 items in the stream. +get :: ParseASN1 [ASN1] +get = P $ \list -> Right (list, list) + +-- | Puts the given list of ASN.1 items as the remainder of the stream and +-- returns @()@. +put :: [ASN1] -> ParseASN1 () +put list = P $ \_ -> Right ((), list) + +-- | Run the parse monad over the elements of the next container of specified +-- type. Throws an error if there is no next container of the specified type. +onNextContainer :: ASN1ConstructionType -> ParseASN1 a -> ParseASN1 a +onNextContainer ty f = + getNextContainer ty >>= either throwParseError pure . runParseASN1 f + +-- | As for 'onNextContainer', except that it does not throw an error if there +-- is no next container of the specified type. +onNextContainerMaybe :: + ASN1ConstructionType + -> ParseASN1 a + -> ParseASN1 (Maybe a) +onNextContainerMaybe ty f = + getNextContainerMaybe ty >>= \case + Nothing -> pure Nothing + Just list -> either throwParseError (pure . Just) $ runParseASN1 f list + +-- | Get the next container of the specified type and return a list of all its +-- ASN.1 elements. Throws a parse error if there is no next container of the +-- specified type. +getNextContainer :: ASN1ConstructionType -> ParseASN1 [ASN1] +getNextContainer ty = + get >>= \case + [] -> throwParseError "empty" + (item : rest) + | item == Start ty -> do + let (list, rest') = getConstructedEnd 0 rest + put rest' >> pure list + | otherwise -> throwParseError "not an expected container" + +-- | As for 'getNextContainer', except that it does not throw an error if there +-- is no next container of the specified type. +getNextContainerMaybe :: ASN1ConstructionType -> ParseASN1 (Maybe [ASN1]) +getNextContainerMaybe ty = + get >>= \case + [] -> pure Nothing + (item : rest) + | item == Start ty -> do + let (list, rest') = getConstructedEnd 0 rest + put rest' >> pure (Just list) + | otherwise -> pure Nothing + +-- | Get the next ASN.1 item in a stream of ASN.1 items. +getNext :: ParseASN1 ASN1 +getNext = + get >>= \case + [] -> throwParseError "empty" + (item : rest) -> put rest >> pure item + +-- | Applies the given function to the next ASN.1 item in a stream of ASN.1 +-- items, if there is one. +getNextMaybe :: (ASN1 -> Maybe a) -> ParseASN1 (Maybe a) +getNextMaybe f = + get >>= \case + [] -> pure Nothing + list@(item : rest) -> do + let result = f item + case result of + Nothing -> put list + Just _ -> put rest + pure result + +-- | Are there any more ASN.1 items in the stream? +hasNext :: ParseASN1 Bool +hasNext = not . null <$> get + +-- | Get the object from the next ASN.1 item in a stream of ASN.1 items. +-- Throws a parse error if the object cannot be obtained from the item. +getObject :: ASN1Object a => ParseASN1 a +getObject = do + list <- get + case fromASN1 list of + Left err -> throwParseError err + Right (object, rest) -> put rest >> pure object + +-- | Get many items from the stream until there are none left. +getMany :: ParseASN1 a -> ParseASN1 [a] +getMany getOne = + hasNext >>= \case + True -> liftM2 (:) getOne (getMany getOne) + False -> pure []