packages feed

spdx 0.2.2.0 → 1

raw patch · 14 files changed

+375/−1062 lines, 14 filesdep +Cabaldep +QuickCheckdep +base-compatdep −ghc-primdep ~basedep ~tastydep ~tasty-quickcheck

Dependencies added: Cabal, QuickCheck, base-compat, containers

Dependencies removed: ghc-prim

Dependency ranges changed: base, tasty, tasty-quickcheck

Files

CHANGELOG.md view
@@ -1,3 +1,7 @@+1++- Move to use `Distribution.SPDX` (from `Cabal`) types.+ 0.2.2.0  - Update license list to v2.6
+ bench/Bench.hs view
@@ -0,0 +1,39 @@+module Main (main) where++import Generators+import Test.QuickCheck+import Test.QuickCheck.Random (mkQCGen)++import Distribution.SPDX+import Distribution.SPDX.Extra++main :: IO ()+main = quickCheckWith args $+    forAll (scaleGen (`div` 3) exprGen) $ \e' -> case e' of+        NONE      -> True+        License e -> isOsiApprovedExpr e == isOsiApprovedExpr' e+  where+    args = stdArgs+        { replay = Just (mkQCGen 1337, 0)+        , maxSuccess = 500+        }++osiLicenseIds :: [LicenseId]+osiLicenseIds = filter licenseIsOsiApproved [minBound .. maxBound]++osiLicenseExpr :: LicenseExpression+osiLicenseExpr = foldr1 EAnd $ map (\l -> ELicense (ELicenseId l) Nothing) osiLicenseIds++isOsiApprovedExpr :: LicenseExpression -> Bool+isOsiApprovedExpr (ELicense _ (Just _)) = False+isOsiApprovedExpr (ELicense sl Nothing) = simple sl+isOsiApprovedExpr (EAnd e1 e2)          = isOsiApprovedExpr e1 && isOsiApprovedExpr e2+isOsiApprovedExpr (EOr e1 e2)           = isOsiApprovedExpr e1 || isOsiApprovedExpr e2++simple :: SimpleLicenseExpression -> Bool+simple (ELicenseId i)     = licenseIsOsiApproved i+simple (ELicenseIdPlus _) = False -- we don't know ranges+simple (ELicenseRef _)    = False++isOsiApprovedExpr' :: LicenseExpression -> Bool+isOsiApprovedExpr' e = License e `satisfies` License osiLicenseExpr
spdx.cabal view
@@ -1,24 +1,28 @@+cabal-version:       2.2 name:                spdx-version:             0.2.2.0-synopsis:            SPDX license expression language-description:         Implementation of <http://spdx.org/sites/spdx/files/SPDX-2.0.pdf SPDX> related functionality.+version:             1++synopsis:            SPDX license expression language, Extras+category:            Data+description:         Cabal provides SPDX types. This package provides some extras.+ homepage:            https://github.com/phadej/spdx-license:             BSD3+license:             BSD-3-Clause license-file:        LICENSE author:              Oleg Grenrus <oleg.grenrus@iki.fi> maintainer:          Oleg Grenrus <oleg.grenrus@iki.fi>-copyright:           (c) 2015 Oleg Grenrus-category:            Data+copyright:           (c) 2015-2018 Oleg Grenrus build-type:          Simple+ extra-source-files:  README.md CHANGELOG.md-cabal-version:       >=1.10 tested-with:-  GHC==7.4.2,-  GHC==7.6.3,-  GHC==7.8.4,-  GHC==7.10.3,-  GHC==8.0.2,-  GHC==8.2.1+  GHC ==7.6.3+   || ==7.8.4+   || ==7.10.3+   || ==8.0.2+   || ==8.2.2+   || ==8.4.4+   || ==8.6.1  source-repository head   type: git@@ -26,27 +30,22 @@  library   default-language:    Haskell98-  exposed-modules:     Data.SPDX,-                       Data.SPDX.LatticeSyntax-  other-modules:       Data.SPDX.Licenses,-                       Data.SPDX.Types,-                       Data.SPDX.Parser,-                       Data.SPDX.Pretty,-                       Data.SPDX.Ranges-  other-extensions:    CPP-                       DeriveFunctor,-                       DeriveFoldable,-                       DeriveTraversable,-                       DeriveDataTypeable-  if impl(ghc >=7.2)-    other-extensions:  DeriveGeneric+  exposed-modules:+    Distribution.SPDX.Extra+    Distribution.SPDX.Extra.Internal+  other-extensions:+    CPP+    DeriveFunctor,+    DeriveFoldable,+    DeriveTraversable,+    DeriveDataTypeable   hs-source-dirs:      src/   ghc-options:         -Wall-  build-depends:       base              >=4.2 && <4.11,-                       transformers      >=0.3 && <0.6-  if impl(ghc >=7.2 && <7.5)-    build-depends: ghc-prim-+  build-depends:+    , base              >=4.3.0.0 && <4.13+    , Cabal             >=2.4.0.1 && <2.5+    , containers        >=0.5.0.0 && <0.7+    , transformers      >=0.3     && <0.6  test-suite test   type:                exitcode-stdio-1.0@@ -55,7 +54,25 @@   default-language:    Haskell98   hs-source-dirs:      tests   ghc-options:         -Wall-  build-depends:       base              >=4.5  && <4.11,-                       tasty             >=0.10 && <0.12,-                       tasty-quickcheck  >=0.8  && <0.10,-                       spdx+  build-depends:+    , base+    , base-compat       ^>=0.10.5+    , Cabal+    , spdx+    , tasty             ^>=1.1.0.4+    , tasty-quickcheck  ^>=0.10++benchmark bench+  type:                exitcode-stdio-1.0+  main-is:             Bench.hs+  other-modules:       Generators+  default-language:    Haskell98+  hs-source-dirs:      tests bench+  ghc-options:         -Wall+  build-depends:+    , base+    , base-compat       ^>=0.10.5+    , Cabal+    , spdx+    , QuickCheck       ^>=2.12.6.1+    , tasty-quickcheck ^>=0.10
− src/Data/SPDX.hs
@@ -1,93 +0,0 @@-{-# LANGUAGE CPP #-}-#if __GLASGOW_HASKELL__ >= 701-{-# LANGUAGE Safe #-}-#endif--- |--- Module      : Data.SPDX--- Description : SPDX licenses and expression language--- Copyright   : (c) 2015 Oleg Grenrus--- License     : BSD3--- Maintainer  : Oleg Grenrus <oleg.grenrus@iki.fi>----module Data.SPDX (-  -- * Types-    LicenseId-  , getLicenseId-  , LicenseExceptionId-  , getLicenseExceptionId-  , LicenseRef(..)-  , LicenseExpression(..)-  -- * Data-  , licenses-  , licenseIdentifiers-  , mkLicenseId-  , isOsiApproved-  , licenseExceptions-  -- ** Ranges-  , licenseRanges-  , lookupLicenseRange-  -- * Parsing-  , parseExpression-  , unsafeParseExpr-  -- * Prettifying-  -- | Inverse of parsing-  , prettyLicenseId-  , prettyLicenseExceptionId-  , prettyLicenseRef-  , prettyLicenseExpression-  -- * Logic-  , satisfies-  , equivalent-  ) where--import Data.SPDX.LatticeSyntax (LatticeSyntax(..))-import qualified Data.SPDX.LatticeSyntax as LS-import           Data.SPDX.Licenses-import           Data.SPDX.Parser-import           Data.SPDX.Pretty-import           Data.SPDX.Ranges-import           Data.SPDX.Types--data Lic = Lic (Either LicenseRef LicenseId) (Maybe LicenseExceptionId)-  deriving (Eq, Ord, Show, Read)--exprToLSLic :: LicenseExpression -> LatticeSyntax Lic-exprToLSLic (ELicense False l e) = LVar (Lic l e)-exprToLSLic (ELicense True (Right l) e) = foldr1 LJoin $ map (\l' -> LVar $ Lic (Right l') e) $ lookupLicenseRange l--- We don't know anything about newer license references-exprToLSLic (ELicense True (Left l) e) = LVar (Lic (Left l) e)-exprToLSLic (EConjunction a b) = LMeet (exprToLSLic a) (exprToLSLic b)-exprToLSLic (EDisjunction a b) = LJoin (exprToLSLic a) (exprToLSLic b)---- |------ @⟦ satisfies a b ⟧ ≡ a ≥ b ≡ a ∧ b = b @------ >>> unsafeParseExpr "GPL-3.0" `satisfies` unsafeParseExpr "ISC AND MIT"--- False------ >>> unsafeParseExpr "Zlib" `satisfies` unsafeParseExpr "ISC AND MIT AND Zlib"--- True------ >>> unsafeParseExpr "(MIT OR GPL-2.0)" `satisfies` unsafeParseExpr "(ISC AND MIT)"--- True------ >>> unsafeParseExpr "(MIT AND GPL-2.0)" `satisfies` unsafeParseExpr "(MIT AND GPL-2.0)"--- True------ >>> unsafeParseExpr "(MIT AND GPL-2.0)" `satisfies` unsafeParseExpr "(ISC AND GPL-2.0)"--- False-satisfies :: LicenseExpression -- ^ package license-          -> LicenseExpression -- ^ license policy-          -> Bool-satisfies a b = exprToLSLic b `LS.preorder` exprToLSLic a---- | Check wheather two 'LicenseExpression' are equivalent.------ >>> unsafeParseExpr "(MIT AND GPL-2.0)" `equivalent` unsafeParseExpr "(GPL-2.0 AND MIT)"--- True------ >>> unsafeParseExpr "MIT" `equivalent` unsafeParseExpr "MIT OR BSD-3-Clause"--- False-equivalent :: LicenseExpression -> LicenseExpression -> Bool-equivalent a b = exprToLSLic a `LS.equivalent` exprToLSLic b
− src/Data/SPDX/LatticeSyntax.hs
@@ -1,151 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE DeriveFoldable #-}-{-# LANGUAGE DeriveTraversable #-}-{-# LANGUAGE DeriveDataTypeable #-}-#if __GLASGOW_HASKELL__ >= 701-#if __GLASGOW_HASKELL__ >= 703-{-# LANGUAGE Safe #-}-#else-{-# LANGUAGE Trustworthy #-}-#endif-#endif--- |--- Module      : Data.SPDX.LatticeSyntax--- Description : General lattice tools--- Copyright   : (c) 2015 Oleg Grenrus--- License     : BSD3--- Maintainer  : Oleg Grenrus <oleg.grenrus@iki.fi>------ Inspired by <http://www.well-typed.com/blog/2014/12/simple-smt-solver/ Simple SMT Solver>.------ In future this module will probably be moved into separate package.-module Data.SPDX.LatticeSyntax (LatticeSyntax(..), dual, freeVars, equivalent, preorder, satisfiable) where--import Control.Applicative-import Control.Monad-import Control.Monad.Trans.State-import Data.Data-import Data.Foldable-import Data.Traversable-import Prelude hiding (all, or)--data LatticeSyntax a = LVar a-                     | LBound Bool-                     | LJoin (LatticeSyntax a) (LatticeSyntax a)-                     | LMeet (LatticeSyntax a) (LatticeSyntax a)-  deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable, Typeable, Data)--instance Applicative LatticeSyntax where-  pure  = return-  (<*>) = ap--instance Monad LatticeSyntax where-  return = LVar-  LVar x    >>= f = f x-  LBound b  >>= _ = LBound b-  LJoin a b >>= f = LJoin (a >>= f) (b >>= f)-  LMeet a b >>= f = LMeet (a >>= f) (b >>= f)--freeVars :: LatticeSyntax a -> [a]-freeVars = toList--dual :: LatticeSyntax a -> LatticeSyntax a-dual (LVar v) = LVar v-dual (LBound t) = LBound $ not t-dual (LJoin a b) = LMeet (dual a) (dual b)-dual (LMeet a b) = LJoin (dual a) (dual b)---- | Test for equivalence.------ >>> equivalent (LMeet (LVar 'a') (LVar 'b')) (LMeet (LVar 'b') (LVar 'a'))--- True------ >>> equivalent (LVar 'a') (LMeet (LVar 'a') (LVar 'a'))--- True------ >>> equivalent (LMeet (LVar 'a') (LVar 'b')) (LMeet (LVar 'b') (LVar 'b'))--- False-equivalent :: Eq a => LatticeSyntax a -> LatticeSyntax a -> Bool-equivalent a b = all (uncurry (==)) . runEval $ p-  where p = (,) <$> evalLattice a <*> evalLattice b---- | Test for preorder.------ @ a ≤ b ⇔ a ∨ b ≡ b ⇔ a ≡ a ∧ b @------ >>> preorder (LVar 'a' `LMeet` LVar 'b') (LVar 'a')--- True------ >>> preorder (LVar 'a') (LVar 'a' `LMeet` LVar 'b')--- False-preorder :: Eq a => LatticeSyntax a -> LatticeSyntax a -> Bool-preorder a b = (a `LJoin` b) `equivalent` b---- | Return `True` if for some variable assigment expression evaluates to `True`.-satisfiable :: Eq a => LatticeSyntax a -> Bool-satisfiable = or . runEval . evalLattice--newtype Eval v a = Eval { unEval :: StateT [(v, Bool)] [] a }--instance Functor (Eval v) where-  fmap = liftM--instance Applicative (Eval v) where-  pure = return-  (<*>) = ap--instance Alternative (Eval v) where-  empty = mzero-  (<|>) = mplus--instance Monad (Eval v) where-  return = Eval . return-  Eval m >>= k = Eval $ m >>= unEval . k--instance MonadPlus (Eval v) where-  mzero = Eval mzero-  Eval a `mplus` Eval b = Eval $ a `mplus` b--runEval :: Eval v a -> [a]-runEval act = evalStateT (unEval act) []--evalLattice :: Eq v => LatticeSyntax v -> Eval v Bool-evalLattice (LVar v)    = guess v-evalLattice (LBound b)  = return b-evalLattice (LJoin a b) = evalLattice a ||^ evalLattice b-evalLattice (LMeet a b) = evalLattice a &&^ evalLattice b--guess :: Eq v => v -> Eval v Bool-guess v = Eval $ do-  st <- get-  let remember b = put ((v, b) : st) >> return b-  case lookup v st of-    Just b  -> return b-    Nothing -> remember True <|> remember False---- From Control.Monad.Extra of extra---- | Like @if@, but where the test can be monadic.-ifM :: Monad m => m Bool -> m a -> m a -> m a-ifM b t f = do b' <- b; if b' then t else f---- | The lazy '||' operator lifted to a monad. If the first---   argument evaluates to 'True' the second argument will not---   be evaluated.------ > Just True  ||^ undefined  == Just True--- > Just False ||^ Just True  == Just True--- > Just False ||^ Just False == Just False-(||^) :: Monad m => m Bool -> m Bool -> m Bool-(||^) a b = ifM a (return True) b---- | The lazy '&&' operator lifted to a monad. If the first---   argument evaluates to 'False' the second argument will not---   be evaluated.------ > Just False &&^ undefined  == Just False--- > Just True  &&^ Just True  == Just True--- > Just True  &&^ Just False == Just False-(&&^) :: Monad m => m Bool -> m Bool -> m Bool-(&&^) a b = ifM a b (return False)
− src/Data/SPDX/Licenses.hs
@@ -1,404 +0,0 @@-{-# LANGUAGE CPP #-}-#if __GLASGOW_HASKELL__ >= 701-{-# LANGUAGE Safe #-}-#endif-module Data.SPDX.Licenses (-    licenses-  , licenseIdentifiers-  , mkLicenseId-  , isOsiApproved-  , licenseExceptions-  ) where--import Data.Foldable-import Data.Maybe--import Data.SPDX.Types--licenseExceptions :: [LicenseExceptionId]-licenseExceptions = map LicenseExceptionId-    [ "389-exception"-    , "Autoconf-exception-2.0"-    , "Autoconf-exception-3.0"-    , "Bison-exception-2.2"-    , "Classpath-exception-2.0"-    , "CLISP-exception-2.0"-    , "DigiRule-FOSS-exception"-    , "eCos-exception-2.0"-    , "Fawkes-Runtime-exception"-    , "FLTK-exception"-    , "Font-exception-2.0"-    , "freertos-exception-2.0"-    , "GCC-exception-2.0"-    , "GCC-exception-3.1"-    , "gnu-javamail-exception"-    , "i2p-gpl-java-exception"-    , "Libtool-exception"-    , "LZMA-exception"-    , "mif-exception"-    , "Nokia-Qt-exception-1.1"-    , "OCCT-exception-1.0"-    , "openvpn-openssl-exception"-    , "Qwt-exception-1.0"-    , "u-boot-exception-2.0"-    , "WxWindows-exception-3.1"-    ]---- | A list of SPDX licenses identifiers.------ See <http://spdx.org/licenses/>.-licenseIdentifiers :: [LicenseId]-licenseIdentifiers = map fstOf3 licenses--fstOf3 :: (a, b, c) -> a-fstOf3 (x,_,_) = x----sndOf3 :: (a, b, c) -> b---sndOf3 (_,x,_) = x--trdOf3 :: (a, b, c) -> c-trdOf3 (_,_,x) = x---- | Lookup `LicenseId` by string representation-mkLicenseId :: String -> Maybe LicenseId-mkLicenseId str = find ((== str) . getLicenseId) licenseIdentifiers---- | Whether license is OSI approved------ See <http://opensource.org/licenses/alphabetical>-isOsiApproved :: LicenseId -> Bool-isOsiApproved l = trdOf3 $ fromJust $ find ((==l) . fstOf3) licenses---- | A list of `LicenseId`, license name and whether the license is OSI approved.------ See <http://spdx.org/licenses/>.-licenses :: [(LicenseId, String, Bool)]-licenses =-  [ (LicenseId "0BSD", "BSD Zero Clause License", True)-  , (LicenseId "AAL", "Attribution Assurance License", True)-  , (LicenseId "ADSL", "Amazon Digital Services License", False)-  , (LicenseId "AFL-1.1", "Academic Free License v1.1", True)-  , (LicenseId "AFL-1.2", "Academic Free License v1.2", True)-  , (LicenseId "AFL-2.0", "Academic Free License v2.0", True)-  , (LicenseId "AFL-2.1", "Academic Free License v2.1", True)-  , (LicenseId "AFL-3.0", "Academic Free License v3.0", True)-  , (LicenseId "AGPL-1.0", "Affero General Public License v1.0", False)-  , (LicenseId "AGPL-3.0", "GNU Affero General Public License v3.0", True)-  , (LicenseId "AMDPLPA", "AMD's plpa_map.c License", False)-  , (LicenseId "AML", "Apple MIT License", False)-  , (LicenseId "AMPAS", "Academy of Motion Picture Arts and Sciences BSD", False)-  , (LicenseId "ANTLR-PD", "ANTLR Software Rights Notice", False)-  , (LicenseId "APAFML", "Adobe Postscript AFM License", False)-  , (LicenseId "APL-1.0", "Adaptive Public License 1.0", True)-  , (LicenseId "APSL-1.0", "Apple Public Source License 1.0", True)-  , (LicenseId "APSL-1.1", "Apple Public Source License 1.1", True)-  , (LicenseId "APSL-1.2", "Apple Public Source License 1.2", True)-  , (LicenseId "APSL-2.0", "Apple Public Source License 2.0", True)-  , (LicenseId "Abstyles", "Abstyles License", False)-  , (LicenseId "Adobe-2006", "Adobe Systems Incorporated Source Code License Agreement", False)-  , (LicenseId "Adobe-Glyph", "Adobe Glyph List License", False)-  , (LicenseId "Afmparse", "Afmparse License", False)-  , (LicenseId "Aladdin", "Aladdin Free Public License", False)-  , (LicenseId "Apache-1.0", "Apache License 1.0", False)-  , (LicenseId "Apache-1.1", "Apache License 1.1", True)-  , (LicenseId "Apache-2.0", "Apache License 2.0", True)-  , (LicenseId "Artistic-1.0", "Artistic License 1.0", True)-  , (LicenseId "Artistic-1.0-Perl", "Artistic License 1.0 (Perl)", True)-  , (LicenseId "Artistic-1.0-cl8", "Artistic License 1.0 w/clause 8", True)-  , (LicenseId "Artistic-2.0", "Artistic License 2.0", True)-  , (LicenseId "BSD-2-Clause", "BSD 2-clause \"Simplified\" License", True)-  , (LicenseId "BSD-2-Clause-FreeBSD", "BSD 2-clause FreeBSD License", False)-  , (LicenseId "BSD-2-Clause-NetBSD", "BSD 2-clause NetBSD License", False)-  , (LicenseId "BSD-3-Clause", "BSD 3-clause \"New\" or \"Revised\" License", True)-  , (LicenseId "BSD-3-Clause-Attribution", "BSD with attribution", False)-  , (LicenseId "BSD-3-Clause-Clear", "BSD 3-clause Clear License", False)-  , (LicenseId "BSD-3-Clause-LBNL", "Lawrence Berkeley National Labs BSD variant license", False)-  , (LicenseId "BSD-3-Clause-No-Nuclear-License", "BSD 3-Clause No Nuclear License", False)-  , (LicenseId "BSD-3-Clause-No-Nuclear-License-2014", "BSD 3-Clause No Nuclear License 2014", False)-  , (LicenseId "BSD-3-Clause-No-Nuclear-Warranty", "BSD 3-Clause No Nuclear Warranty", False)-  , (LicenseId "BSD-4-Clause", "BSD 4-clause \"Original\" or \"Old\" License", False)-  , (LicenseId "BSD-4-Clause-UC", "BSD-4-Clause (University of California-Specific)", False)-  , (LicenseId "BSD-Protection", "BSD Protection License", False)-  , (LicenseId "BSD-Source-Code", "BSD Source Code Attribution", False)-  , (LicenseId "BSL-1.0", "Boost Software License 1.0", True)-  , (LicenseId "Bahyph", "Bahyph License", False)-  , (LicenseId "Barr", "Barr License", False)-  , (LicenseId "Beerware", "Beerware License", False)-  , (LicenseId "BitTorrent-1.0", "BitTorrent Open Source License v1.0", False)-  , (LicenseId "BitTorrent-1.1", "BitTorrent Open Source License v1.1", False)-  , (LicenseId "Borceux", "Borceux license", False)-  , (LicenseId "CATOSL-1.1", "Computer Associates Trusted Open Source License 1.1", True)-  , (LicenseId "CC-BY-1.0", "Creative Commons Attribution 1.0", False)-  , (LicenseId "CC-BY-2.0", "Creative Commons Attribution 2.0", False)-  , (LicenseId "CC-BY-2.5", "Creative Commons Attribution 2.5", False)-  , (LicenseId "CC-BY-3.0", "Creative Commons Attribution 3.0", False)-  , (LicenseId "CC-BY-4.0", "Creative Commons Attribution 4.0", False)-  , (LicenseId "CC-BY-NC-1.0", "Creative Commons Attribution Non Commercial 1.0", False)-  , (LicenseId "CC-BY-NC-2.0", "Creative Commons Attribution Non Commercial 2.0", False)-  , (LicenseId "CC-BY-NC-2.5", "Creative Commons Attribution Non Commercial 2.5", False)-  , (LicenseId "CC-BY-NC-3.0", "Creative Commons Attribution Non Commercial 3.0", False)-  , (LicenseId "CC-BY-NC-4.0", "Creative Commons Attribution Non Commercial 4.0", False)-  , (LicenseId "CC-BY-NC-ND-1.0", "Creative Commons Attribution Non Commercial No Derivatives 1.0", False)-  , (LicenseId "CC-BY-NC-ND-2.0", "Creative Commons Attribution Non Commercial No Derivatives 2.0", False)-  , (LicenseId "CC-BY-NC-ND-2.5", "Creative Commons Attribution Non Commercial No Derivatives 2.5", False)-  , (LicenseId "CC-BY-NC-ND-3.0", "Creative Commons Attribution Non Commercial No Derivatives 3.0", False)-  , (LicenseId "CC-BY-NC-ND-4.0", "Creative Commons Attribution Non Commercial No Derivatives 4.0", False)-  , (LicenseId "CC-BY-NC-SA-1.0", "Creative Commons Attribution Non Commercial Share Alike 1.0", False)-  , (LicenseId "CC-BY-NC-SA-2.0", "Creative Commons Attribution Non Commercial Share Alike 2.0", False)-  , (LicenseId "CC-BY-NC-SA-2.5", "Creative Commons Attribution Non Commercial Share Alike 2.5", False)-  , (LicenseId "CC-BY-NC-SA-3.0", "Creative Commons Attribution Non Commercial Share Alike 3.0", False)-  , (LicenseId "CC-BY-NC-SA-4.0", "Creative Commons Attribution Non Commercial Share Alike 4.0", False)-  , (LicenseId "CC-BY-ND-1.0", "Creative Commons Attribution No Derivatives 1.0", False)-  , (LicenseId "CC-BY-ND-2.0", "Creative Commons Attribution No Derivatives 2.0", False)-  , (LicenseId "CC-BY-ND-2.5", "Creative Commons Attribution No Derivatives 2.5", False)-  , (LicenseId "CC-BY-ND-3.0", "Creative Commons Attribution No Derivatives 3.0", False)-  , (LicenseId "CC-BY-ND-4.0", "Creative Commons Attribution No Derivatives 4.0", False)-  , (LicenseId "CC-BY-SA-1.0", "Creative Commons Attribution Share Alike 1.0", False)-  , (LicenseId "CC-BY-SA-2.0", "Creative Commons Attribution Share Alike 2.0", False)-  , (LicenseId "CC-BY-SA-2.5", "Creative Commons Attribution Share Alike 2.5", False)-  , (LicenseId "CC-BY-SA-3.0", "Creative Commons Attribution Share Alike 3.0", False)-  , (LicenseId "CC-BY-SA-4.0", "Creative Commons Attribution Share Alike 4.0", False)-  , (LicenseId "CC0-1.0", "Creative Commons Zero v1.0 Universal", False)-  , (LicenseId "CDDL-1.0", "Common Development and Distribution License 1.0", True)-  , (LicenseId "CDDL-1.1", "Common Development and Distribution License 1.1", False)-  , (LicenseId "CECILL-1.0", "CeCILL Free Software License Agreement v1.0", False)-  , (LicenseId "CECILL-1.1", "CeCILL Free Software License Agreement v1.1", False)-  , (LicenseId "CECILL-2.0", "CeCILL Free Software License Agreement v2.0", False)-  , (LicenseId "CECILL-2.1", "CeCILL Free Software License Agreement v2.1", True)-  , (LicenseId "CECILL-B", "CeCILL-B Free Software License Agreement", False)-  , (LicenseId "CECILL-C", "CeCILL-C Free Software License Agreement", False)-  , (LicenseId "CNRI-Jython", "CNRI Jython License", False)-  , (LicenseId "CNRI-Python", "CNRI Python License", True)-  , (LicenseId "CNRI-Python-GPL-Compatible", "CNRI Python Open Source GPL Compatible License Agreement", False)-  , (LicenseId "CPAL-1.0", "Common Public Attribution License 1.0", True)-  , (LicenseId "CPL-1.0", "Common Public License 1.0", True)-  , (LicenseId "CPOL-1.02", "Code Project Open License 1.02", False)-  , (LicenseId "CUA-OPL-1.0", "CUA Office Public License v1.0", True)-  , (LicenseId "Caldera", "Caldera License", False)-  , (LicenseId "ClArtistic", "Clarified Artistic License", False)-  , (LicenseId "Condor-1.1", "Condor Public License v1.1", False)-  , (LicenseId "Crossword", "Crossword License", False)-  , (LicenseId "CrystalStacker", "CrystalStacker License", False)-  , (LicenseId "Cube", "Cube License", False)-  , (LicenseId "D-FSL-1.0", "Deutsche Freie Software Lizenz", False)-  , (LicenseId "DOC", "DOC License", False)-  , (LicenseId "DSDP", "DSDP License", False)-  , (LicenseId "Dotseqn", "Dotseqn License", False)-  , (LicenseId "ECL-1.0", "Educational Community License v1.0", True)-  , (LicenseId "ECL-2.0", "Educational Community License v2.0", True)-  , (LicenseId "EFL-1.0", "Eiffel Forum License v1.0", True)-  , (LicenseId "EFL-2.0", "Eiffel Forum License v2.0", True)-  , (LicenseId "EPL-1.0", "Eclipse Public License 1.0", True)-  , (LicenseId "EUDatagrid", "EU DataGrid Software License", True)-  , (LicenseId "EUPL-1.0", "European Union Public License 1.0", False)-  , (LicenseId "EUPL-1.1", "European Union Public License 1.1", True)-  , (LicenseId "Entessa", "Entessa Public License v1.0", True)-  , (LicenseId "ErlPL-1.1", "Erlang Public License v1.1", False)-  , (LicenseId "Eurosym", "Eurosym License", False)-  , (LicenseId "FSFAP", "FSF All Permissive License", False)-  , (LicenseId "FSFUL", "FSF Unlimited License", False)-  , (LicenseId "FSFULLR", "FSF Unlimited License (with License Retention)", False)-  , (LicenseId "FTL", "Freetype Project License", False)-  , (LicenseId "Fair", "Fair License", True)-  , (LicenseId "Frameworx-1.0", "Frameworx Open License 1.0", True)-  , (LicenseId "FreeImage", "FreeImage Public License v1.0", False)-  , (LicenseId "GFDL-1.1", "GNU Free Documentation License v1.1", False)-  , (LicenseId "GFDL-1.2", "GNU Free Documentation License v1.2", False)-  , (LicenseId "GFDL-1.3", "GNU Free Documentation License v1.3", False)-  , (LicenseId "GL2PS", "GL2PS License", False)-  , (LicenseId "GPL-1.0", "GNU General Public License v1.0 only", False)-  , (LicenseId "GPL-2.0", "GNU General Public License v2.0 only", True)-  , (LicenseId "GPL-3.0", "GNU General Public License v3.0 only", True)-  , (LicenseId "Giftware", "Giftware License", False)-  , (LicenseId "Glide", "3dfx Glide License", False)-  , (LicenseId "Glulxe", "Glulxe License", False)-  , (LicenseId "HPND", "Historic Permission Notice and Disclaimer", True)-  , (LicenseId "HaskellReport", "Haskell Language Report License", False)-  , (LicenseId "IBM-pibs", "IBM PowerPC Initialization and Boot Software", False)-  , (LicenseId "ICU", "ICU License", False)-  , (LicenseId "IJG", "Independent JPEG Group License", False)-  , (LicenseId "IPA", "IPA Font License", True)-  , (LicenseId "IPL-1.0", "IBM Public License v1.0", True)-  , (LicenseId "ISC", "ISC License", True)-  , (LicenseId "ImageMagick", "ImageMagick License", False)-  , (LicenseId "Imlib2", "Imlib2 License", False)-  , (LicenseId "Info-ZIP", "Info-ZIP License", False)-  , (LicenseId "Intel", "Intel Open Source License", True)-  , (LicenseId "Intel-ACPI", "Intel ACPI Software License Agreement", False)-  , (LicenseId "Interbase-1.0", "Interbase Public License v1.0", False)-  , (LicenseId "JSON", "JSON License", False)-  , (LicenseId "JasPer-2.0", "JasPer License", False)-  , (LicenseId "LAL-1.2", "Licence Art Libre 1.2", False)-  , (LicenseId "LAL-1.3", "Licence Art Libre 1.3", False)-  , (LicenseId "LGPL-2.0", "GNU Library General Public License v2 only", True)-  , (LicenseId "LGPL-2.1", "GNU Lesser General Public License v2.1 only", True)-  , (LicenseId "LGPL-3.0", "GNU Lesser General Public License v3.0 only", True)-  , (LicenseId "LGPLLR", "Lesser General Public License For Linguistic Resources", False)-  , (LicenseId "LPL-1.0", "Lucent Public License Version 1.0", True)-  , (LicenseId "LPL-1.02", "Lucent Public License v1.02", True)-  , (LicenseId "LPPL-1.0", "LaTeX Project Public License v1.0", False)-  , (LicenseId "LPPL-1.1", "LaTeX Project Public License v1.1", False)-  , (LicenseId "LPPL-1.2", "LaTeX Project Public License v1.2", False)-  , (LicenseId "LPPL-1.3a", "LaTeX Project Public License v1.3a", False)-  , (LicenseId "LPPL-1.3c", "LaTeX Project Public License v1.3c", True)-  , (LicenseId "Latex2e", "Latex2e License", False)-  , (LicenseId "Leptonica", "Leptonica License", False)-  , (LicenseId "LiLiQ-P-1.1", "Licence Libre du Qu\233bec \8211 Permissive version 1.1", True)-  , (LicenseId "LiLiQ-R-1.1", "Licence Libre du Qu\233bec \8211 R\233ciprocit\233 version 1.1", True)-  , (LicenseId "LiLiQ-Rplus-1.1", "Licence Libre du Qu\233bec \8211 R\233ciprocit\233 forte version 1.1", True)-  , (LicenseId "Libpng", "libpng License", False)-  , (LicenseId "MIT", "MIT License", True)-  , (LicenseId "MIT-CMU", "CMU License", False)-  , (LicenseId "MIT-advertising", "Enlightenment License (e16)", False)-  , (LicenseId "MIT-enna", "enna License", False)-  , (LicenseId "MIT-feh", "feh License", False)-  , (LicenseId "MITNFA", "MIT +no-false-attribs license", False)-  , (LicenseId "MPL-1.0", "Mozilla Public License 1.0", True)-  , (LicenseId "MPL-1.1", "Mozilla Public License 1.1", True)-  , (LicenseId "MPL-2.0", "Mozilla Public License 2.0", True)-  , (LicenseId "MPL-2.0-no-copyleft-exception", "Mozilla Public License 2.0 (no copyleft exception)", True)-  , (LicenseId "MS-PL", "Microsoft Public License", True)-  , (LicenseId "MS-RL", "Microsoft Reciprocal License", True)-  , (LicenseId "MTLL", "Matrix Template Library License", False)-  , (LicenseId "MakeIndex", "MakeIndex License", False)-  , (LicenseId "MirOS", "MirOS Licence", True)-  , (LicenseId "Motosoto", "Motosoto License", True)-  , (LicenseId "Multics", "Multics License", True)-  , (LicenseId "Mup", "Mup License", False)-  , (LicenseId "NASA-1.3", "NASA Open Source Agreement 1.3", True)-  , (LicenseId "NBPL-1.0", "Net Boolean Public License v1", False)-  , (LicenseId "NCSA", "University of Illinois/NCSA Open Source License", True)-  , (LicenseId "NGPL", "Nethack General Public License", True)-  , (LicenseId "NLOD-1.0", "Norwegian Licence for Open Government Data", False)-  , (LicenseId "NLPL", "No Limit Public License", False)-  , (LicenseId "NOSL", "Netizen Open Source License", False)-  , (LicenseId "NPL-1.0", "Netscape Public License v1.0", False)-  , (LicenseId "NPL-1.1", "Netscape Public License v1.1", False)-  , (LicenseId "NPOSL-3.0", "Non-Profit Open Software License 3.0", True)-  , (LicenseId "NRL", "NRL License", False)-  , (LicenseId "NTP", "NTP License", True)-  , (LicenseId "Naumen", "Naumen Public License", True)-  , (LicenseId "Net-SNMP", "Net-SNMP License", False)-  , (LicenseId "NetCDF", "NetCDF license", False)-  , (LicenseId "Newsletr", "Newsletr License", False)-  , (LicenseId "Nokia", "Nokia Open Source License", True)-  , (LicenseId "Noweb", "Noweb License", False)-  , (LicenseId "Nunit", "Nunit License", False)-  , (LicenseId "OCCT-PL", "Open CASCADE Technology Public License", False)-  , (LicenseId "OCLC-2.0", "OCLC Research Public License 2.0", True)-  , (LicenseId "ODbL-1.0", "ODC Open Database License v1.0", False)-  , (LicenseId "OFL-1.0", "SIL Open Font License 1.0", False)-  , (LicenseId "OFL-1.1", "SIL Open Font License 1.1", True)-  , (LicenseId "OGTSL", "Open Group Test Suite License", True)-  , (LicenseId "OLDAP-1.1", "Open LDAP Public License v1.1", False)-  , (LicenseId "OLDAP-1.2", "Open LDAP Public License v1.2", False)-  , (LicenseId "OLDAP-1.3", "Open LDAP Public License v1.3", False)-  , (LicenseId "OLDAP-1.4", "Open LDAP Public License v1.4", False)-  , (LicenseId "OLDAP-2.0", "Open LDAP Public License v2.0 (or possibly 2.0A and 2.0B)", False)-  , (LicenseId "OLDAP-2.0.1", "Open LDAP Public License v2.0.1", False)-  , (LicenseId "OLDAP-2.1", "Open LDAP Public License v2.1", False)-  , (LicenseId "OLDAP-2.2", "Open LDAP Public License v2.2", False)-  , (LicenseId "OLDAP-2.2.1", "Open LDAP Public License v2.2.1", False)-  , (LicenseId "OLDAP-2.2.2", "Open LDAP Public License  2.2.2", False)-  , (LicenseId "OLDAP-2.3", "Open LDAP Public License v2.3", False)-  , (LicenseId "OLDAP-2.4", "Open LDAP Public License v2.4", False)-  , (LicenseId "OLDAP-2.5", "Open LDAP Public License v2.5", False)-  , (LicenseId "OLDAP-2.6", "Open LDAP Public License v2.6", False)-  , (LicenseId "OLDAP-2.7", "Open LDAP Public License v2.7", False)-  , (LicenseId "OLDAP-2.8", "Open LDAP Public License v2.8", False)-  , (LicenseId "OML", "Open Market License", False)-  , (LicenseId "OPL-1.0", "Open Public License v1.0", False)-  , (LicenseId "OSET-PL-2.1", "OSET Public License version 2.1", True)-  , (LicenseId "OSL-1.0", "Open Software License 1.0", True)-  , (LicenseId "OSL-1.1", "Open Software License 1.1", False)-  , (LicenseId "OSL-2.0", "Open Software License 2.0", True)-  , (LicenseId "OSL-2.1", "Open Software License 2.1", True)-  , (LicenseId "OSL-3.0", "Open Software License 3.0", True)-  , (LicenseId "OpenSSL", "OpenSSL License", False)-  , (LicenseId "PDDL-1.0", "ODC Public Domain Dedication & License 1.0", False)-  , (LicenseId "PHP-3.0", "PHP License v3.0", True)-  , (LicenseId "PHP-3.01", "PHP License v3.01", False)-  , (LicenseId "Plexus", "Plexus Classworlds License", False)-  , (LicenseId "PostgreSQL", "PostgreSQL License", True)-  , (LicenseId "Python-2.0", "Python License 2.0", True)-  , (LicenseId "QPL-1.0", "Q Public License 1.0", True)-  , (LicenseId "Qhull", "Qhull License", False)-  , (LicenseId "RHeCos-1.1", "Red Hat eCos Public License v1.1", False)-  , (LicenseId "RPL-1.1", "Reciprocal Public License 1.1", True)-  , (LicenseId "RPL-1.5", "Reciprocal Public License 1.5", True)-  , (LicenseId "RPSL-1.0", "RealNetworks Public Source License v1.0", True)-  , (LicenseId "RSA-MD", "RSA Message-Digest License ", False)-  , (LicenseId "RSCPL", "Ricoh Source Code Public License", True)-  , (LicenseId "Rdisc", "Rdisc License", False)-  , (LicenseId "Ruby", "Ruby License", False)-  , (LicenseId "SAX-PD", "Sax Public Domain Notice", False)-  , (LicenseId "SCEA", "SCEA Shared Source License", False)-  , (LicenseId "SGI-B-1.0", "SGI Free Software License B v1.0", False)-  , (LicenseId "SGI-B-1.1", "SGI Free Software License B v1.1", False)-  , (LicenseId "SGI-B-2.0", "SGI Free Software License B v2.0", False)-  , (LicenseId "SISSL", "Sun Industry Standards Source License v1.1", True)-  , (LicenseId "SISSL-1.2", "Sun Industry Standards Source License v1.2", False)-  , (LicenseId "SMLNJ", "Standard ML of New Jersey License", False)-  , (LicenseId "SMPPL", "Secure Messaging Protocol Public License", False)-  , (LicenseId "SNIA", "SNIA Public License 1.1", False)-  , (LicenseId "SPL-1.0", "Sun Public License v1.0", True)-  , (LicenseId "SWL", "Scheme Widget Library (SWL) Software License Agreement", False)-  , (LicenseId "Saxpath", "Saxpath License", False)-  , (LicenseId "Sendmail", "Sendmail License", False)-  , (LicenseId "SimPL-2.0", "Simple Public License 2.0", True)-  , (LicenseId "Sleepycat", "Sleepycat License", True)-  , (LicenseId "Spencer-86", "Spencer License 86", False)-  , (LicenseId "Spencer-94", "Spencer License 94", False)-  , (LicenseId "Spencer-99", "Spencer License 99", False)-  , (LicenseId "SugarCRM-1.1.3", "SugarCRM Public License v1.1.3", False)-  , (LicenseId "TCL", "TCL/TK License", False)-  , (LicenseId "TCP-wrappers", "TCP Wrappers License", False)-  , (LicenseId "TMate", "TMate Open Source License", False)-  , (LicenseId "TORQUE-1.1", "TORQUE v2.5+ Software License v1.1", False)-  , (LicenseId "TOSL", "Trusster Open Source License", False)-  , (LicenseId "UPL-1.0", "Universal Permissive License v1.0", True)-  , (LicenseId "Unicode-DFS-2015", "Unicode License Agreement - Data Files and Software (2015)", False)-  , (LicenseId "Unicode-DFS-2016", "Unicode License Agreement - Data Files and Software (2016)", False)-  , (LicenseId "Unicode-TOU", "Unicode Terms of Use", False)-  , (LicenseId "Unlicense", "The Unlicense", False)-  , (LicenseId "VOSTROM", "VOSTROM Public License for Open Source", False)-  , (LicenseId "VSL-1.0", "Vovida Software License v1.0", True)-  , (LicenseId "Vim", "Vim License", False)-  , (LicenseId "W3C", "W3C Software Notice and License (2002-12-31)", True)-  , (LicenseId "W3C-19980720", "W3C Software Notice and License (1998-07-20)", False)-  , (LicenseId "W3C-20150513", "W3C Software Notice and Document License (2015-05-13)", False)-  , (LicenseId "WTFPL", "Do What The F*ck You Want To Public License", False)-  , (LicenseId "Watcom-1.0", "Sybase Open Watcom Public License 1.0", True)-  , (LicenseId "Wsuipa", "Wsuipa License", False)-  , (LicenseId "X11", "X11 License", False)-  , (LicenseId "XFree86-1.1", "XFree86 License 1.1", False)-  , (LicenseId "XSkat", "XSkat License", False)-  , (LicenseId "Xerox", "Xerox License", False)-  , (LicenseId "Xnet", "X.Net License", True)-  , (LicenseId "YPL-1.0", "Yahoo! Public License v1.0", False)-  , (LicenseId "YPL-1.1", "Yahoo! Public License v1.1", False)-  , (LicenseId "ZPL-1.1", "Zope Public License 1.1", False)-  , (LicenseId "ZPL-2.0", "Zope Public License 2.0", True)-  , (LicenseId "ZPL-2.1", "Zope Public License 2.1", False)-  , (LicenseId "Zed", "Zed License", False)-  , (LicenseId "Zend-2.0", "Zend License v2.0", False)-  , (LicenseId "Zimbra-1.3", "Zimbra Public License v1.3", False)-  , (LicenseId "Zimbra-1.4", "Zimbra Public License v1.4", False)-  , (LicenseId "Zlib", "zlib License", True)-  , (LicenseId "bzip2-1.0.5", "bzip2 and libbzip2 License v1.0.5", False)-  , (LicenseId "bzip2-1.0.6", "bzip2 and libbzip2 License v1.0.6", False)-  , (LicenseId "curl", "curl License", False)-  , (LicenseId "diffmark", "diffmark license", False)-  , (LicenseId "dvipdfm", "dvipdfm License", False)-  , (LicenseId "eGenix", "eGenix.com Public License 1.1.0", False)-  , (LicenseId "gSOAP-1.3b", "gSOAP Public License v1.3b", False)-  , (LicenseId "gnuplot", "gnuplot License", False)-  , (LicenseId "iMatix", "iMatix Standard Function Library Agreement", False)-  , (LicenseId "libtiff", "libtiff License", False)-  , (LicenseId "mpich2", "mpich2 License", False)-  , (LicenseId "psfrag", "psfrag License", False)-  , (LicenseId "psutils", "psutils License", False)-  , (LicenseId "xinetd", "xinetd License", False)-  , (LicenseId "xpp", "XPP License", False)-  , (LicenseId "zlib-acknowledgement", "zlib/libpng License with Acknowledgement", False)-  ]
− src/Data/SPDX/Parser.hs
@@ -1,99 +0,0 @@-{-# LANGUAGE CPP #-}-#if __GLASGOW_HASKELL__ >= 701-{-# LANGUAGE Safe #-}-#endif-module Data.SPDX.Parser (parseExpression, unsafeParseExpr) where--#ifndef MIN_VERSION_base-#define MIN_VERSION_base(x,y,z) 0-#endif--#if !MIN_VERSION_base(4,8,0)-import Control.Applicative-#endif--import Control.Monad-import Data.Char-import Text.ParserCombinators.ReadP--import Data.SPDX.Types-import Data.SPDX.Licenses (licenseIdentifiers, licenseExceptions)--infixl 4 `ap'`---- ReadP isn't Applicative in old enough base-ap' :: Monad m => m (a -> b) -> m a -> m b-ap' = ap--(<<) :: Monad m => m a -> m b -> m a-ma << mb = do-  a <- ma-  _ <- mb-  return a--license :: ReadP LicenseId-license = choice (map f licenseIdentifiers)-  where f l = l <$ string (getLicenseId l)--licenseException :: ReadP LicenseExceptionId-licenseException = choice (map f licenseExceptions)-  where f l = l <$ string (getLicenseExceptionId l)--licenseRef :: ReadP LicenseRef-licenseRef = l `mplus` d-  where l = LicenseRef Nothing <$ string "LicenseRef-" `ap'` idString-        d = (\docId licId -> LicenseRef (Just docId) licId) <$ string "DocumentRef-" `ap'` idString << char ':' << string "LicenseRef-" `ap'` idString--mkLicense ::  ReadP (Either LicenseRef LicenseId) -> ReadP LicenseExpression-mkLicense p = choice-  [ (\l   -> ELicense False l Nothing)  <$> p-  , (\l e -> ELicense False l (Just e)) <$> p << skipSpaces1 << string "WITH" << skipSpaces1 `ap'` licenseException-  , (\l   -> ELicense True  l Nothing)  <$> p << char '+'-  , (\l e -> ELicense True  l (Just e)) <$> p << char '+' << string " WITH " `ap'` licenseException-  ]--elicense :: ReadP LicenseExpression-elicense = mkLicense (Right <$> license)--elicenseRef :: ReadP LicenseExpression-elicenseRef = mkLicense (Left <$> licenseRef)--idString :: ReadP String-idString = munch1 p-  where p '.' = True-        p '-' = True-        p c   = isAlphaNum c--skipSpaces1 :: ReadP ()-skipSpaces1 = () <$ char ' ' << skipSpaces--parens :: ReadP a -> ReadP a-parens = between (char '(') (skipSpaces << char ')')--terminal :: ReadP LicenseExpression-terminal = choice [ elicense-                  , elicenseRef-                  , parens expression-                  ]--conjunction :: ReadP LicenseExpression-conjunction = chainr1 terminal (EConjunction <$ skipSpaces1 << string "AND" << skipSpaces1)--disjunction :: ReadP LicenseExpression-disjunction = chainr1 conjunction (EDisjunction <$ skipSpaces1 << string "OR" << skipSpaces1)--expression :: ReadP LicenseExpression-expression = skipSpaces >> disjunction---- | Parse SPDX License Expression------ >>> parseExpression "LGPL-2.1 OR MIT"--- [EDisjunction (ELicense False (Right (LicenseId "LGPL-2.1")) Nothing) (ELicense False (Right (LicenseId "MIT")) Nothing)]-parseExpression :: String -> [LicenseExpression]-parseExpression = map fst . readP_to_S (expression << skipSpaces << eof)--unsafeParseExpr :: String -> LicenseExpression-unsafeParseExpr s = f . parseExpression $ s-  where f []      = error $ "Failed parse of license expression: " ++ s-        f [l]     = l-        f (_:_:_) = error $ "Ambigious parse of license expression: " ++ s
− src/Data/SPDX/Pretty.hs
@@ -1,43 +0,0 @@-{-# LANGUAGE CPP #-}-#if __GLASGOW_HASKELL__ >= 701-{-# LANGUAGE Safe #-}-#endif--- | Parser inverse.-module Data.SPDX.Pretty-  ( prettyLicenseId-  , prettyLicenseExceptionId-  , prettyLicenseRef-  , prettyLicenseExpression-  ) where--import Data.SPDX.Types--prettyLicenseId :: LicenseId -> String-prettyLicenseId = getLicenseId--prettyLicenseExceptionId :: LicenseExceptionId -> String-prettyLicenseExceptionId = getLicenseExceptionId--prettyLicenseRef :: LicenseRef -> String-prettyLicenseRef (LicenseRef Nothing r)  = "LicenseRef-" ++ r-prettyLicenseRef (LicenseRef (Just d) r) = "DocumentRef-" ++ d ++ ":LicenseRef-" ++ r--prettyLicenseExpression :: LicenseExpression -> String-prettyLicenseExpression = pprExpr 1--pprLicense :: Either LicenseRef LicenseId -> String-pprLicense (Left ref) = prettyLicenseRef ref-pprLicense (Right i)  = prettyLicenseId i--pprExpr :: Int -> LicenseExpression -> String-pprExpr _ (ELicense newer lic exc) = pprLicense lic ++ n ++ e-  where n = if newer then "+" else ""-        e = case exc of-              Just exc' -> " WITH " ++ prettyLicenseExceptionId exc'-              Nothing   -> ""-pprExpr d (EConjunction e1 e2)     = parens (d < 0) $ pprExpr 0 e1 ++ " AND " ++ pprExpr 0 e2-pprExpr d (EDisjunction e1 e2)     = parens (d < 1) $ pprExpr 1 e1 ++ " OR " ++ pprExpr 1 e2--parens :: Bool -> String -> String-parens False s = s-parens True  s  = "(" ++ s ++ ")"
− src/Data/SPDX/Ranges.hs
@@ -1,51 +0,0 @@-{-# LANGUAGE CPP #-}-#if __GLASGOW_HASKELL__ >= 701-{-# LANGUAGE Safe #-}-#endif-module Data.SPDX.Ranges (licenseRanges, lookupLicenseRange) where--import Data.Char-import Data.List-import Data.Maybe--import Data.SPDX.Types-import Data.SPDX.Licenses--licenseRanges :: [[LicenseId]]-licenseRanges = filter longerThanSingleton . map f $ prefixes-  where f p = filter (\l -> p `isPrefixOf` getLicenseId l && restIsNumber (getLicenseId l) p) licenseIdentifiers---- | Lookup newer licenses we know about------ >>> lookupLicenseRange $ fromJust $ mkLicenseId "MIT"--- [LicenseId "MIT"]------ >>> lookupLicenseRange $ fromJust $ mkLicenseId "GPL-2.0"--- [LicenseId "GPL-2.0",LicenseId "GPL-3.0"]------ >>> lookupLicenseRange $ fromJust $ mkLicenseId "LGPL-2.0"--- [LicenseId "LGPL-2.0",LicenseId "LGPL-2.1",LicenseId "LGPL-3.0"]-lookupLicenseRange :: LicenseId -> [LicenseId]-lookupLicenseRange l = fromMaybe [l] $ lookup l ranges'--ranges' :: [(LicenseId, [LicenseId])]-ranges' = map (\r -> (head r, r)) . filter (not . nullOrSingleton) . concatMap tails $ licenseRanges--nullOrSingleton :: [a] -> Bool-nullOrSingleton []      = True-nullOrSingleton [_]     = True-nullOrSingleton (_:_:_) = False--restIsNumber :: String -> String -> Bool-restIsNumber l p = all (\c -> isDigit c || c == 'a' || c == 'b' || c == 'c' || c == '.') (drop (length p) l)--pref :: String -> String-pref = reverse . dropWhile (/= '-') . reverse--prefixes :: [String]-prefixes = nub (filter (not . null) $ map (pref . getLicenseId) licenseIdentifiers)--longerThanSingleton :: [a] -> Bool-longerThanSingleton []      = False-longerThanSingleton [_]     = False-longerThanSingleton (_:_:_) = True
− src/Data/SPDX/Types.hs
@@ -1,69 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveDataTypeable #-}--#if __GLASGOW_HASKELL__ >= 701-{-# LANGUAGE DeriveGeneric #-}-#endif--#if __GLASGOW_HASKELL__ >= 701-#if __GLASGOW_HASKELL__ >= 703-{-# LANGUAGE Safe #-}-#else-{-# LANGUAGE Trustworthy #-}-#endif-#endif-module Data.SPDX.Types (-    LicenseId(..)-  , getLicenseId-  , LicenseExceptionId(..)-  , getLicenseExceptionId-  , LicenseRef(..)-  , LicenseExpression(..)-  ) where--import Data.Data--#if __GLASGOW_HASKELL__ >= 701-import GHC.Generics-#endif--data LicenseRef = LicenseRef-  { lrDocument :: !(Maybe String)-  , lrLicense  :: !String-  }-  deriving (Eq, Ord, Show, Read, Typeable, Data-#if __GLASGOW_HASKELL__ >= 701-           , Generic-#endif-           )---- | Opaque license identifier type.-newtype LicenseId = LicenseId String-  deriving (Eq, Ord, Show, Read, Typeable, Data-#if __GLASGOW_HASKELL__ >= 701-           , Generic-#endif-           )--getLicenseId :: LicenseId -> String-getLicenseId (LicenseId l) = l---- | Opaque license exception identifier type.-newtype LicenseExceptionId = LicenseExceptionId String-  deriving (Eq, Ord, Show, Read, Typeable, Data-#if __GLASGOW_HASKELL__ >= 701-           , Generic-#endif-           )--getLicenseExceptionId :: LicenseExceptionId -> String-getLicenseExceptionId (LicenseExceptionId l) = l--data LicenseExpression = ELicense !Bool !(Either LicenseRef LicenseId) !(Maybe LicenseExceptionId)-                       | EConjunction !LicenseExpression !LicenseExpression-                       | EDisjunction !LicenseExpression !LicenseExpression-  deriving (Eq, Ord, Show, Read, Typeable, Data-#if __GLASGOW_HASKELL__ >= 701-           , Generic-#endif-           )
+ src/Distribution/SPDX/Extra.hs view
@@ -0,0 +1,77 @@+-- |+--+module Distribution.SPDX.Extra (+  -- * Types+  -- | We don't export the constructors, as they change with Cabal version.+  License,+  LicenseExpression,+  SimpleLicenseExpression,+  LicenseId,+  LicenseExceptionId,++  -- * Logic+  satisfies,+  equivalent,+  ) where++import Distribution.SPDX+       (License (..), LicenseExceptionId, LicenseExpression (..), LicenseId,+       SimpleLicenseExpression (..))+import Distribution.SPDX.Extra.Internal (LatticeSyntax (..))++import qualified Distribution.SPDX.Extra.Internal as LS++-- |+--+-- @⟦ satisfies a b ⟧ ≡ a ≥ b ≡ a ∧ b = b @+--+-- >>> unsafeParseExpr "GPL-3.0-only" `satisfies` unsafeParseExpr "ISC AND MIT"+-- False+--+-- >>> unsafeParseExpr "Zlib" `satisfies` unsafeParseExpr "ISC AND MIT AND Zlib"+-- True+--+-- >>> unsafeParseExpr "(MIT OR GPL-2.0-only)" `satisfies` unsafeParseExpr "(ISC AND MIT)"+-- True+--+-- >>> unsafeParseExpr "(MIT AND GPL-2.0-only)" `satisfies` unsafeParseExpr "(MIT AND GPL-2.0-only)"+-- True+--+-- >>> unsafeParseExpr "(MIT AND GPL-2.0-only)" `satisfies` unsafeParseExpr "(ISC AND GPL-2.0-only)"+-- False+--+satisfies :: License -- ^ package license+          -> License -- ^ license policy+          -> Bool+satisfies a b = exprToLSLic b `LS.preorder` exprToLSLic a++-- | Check wheather two 'LicenseExpression' are equivalent.+--+-- >>> unsafeParseExpr "(MIT AND GPL-2.0-only)" `equivalent` unsafeParseExpr "(GPL-2.0-only AND MIT)"+-- True+--+-- >>> unsafeParseExpr "MIT" `equivalent` unsafeParseExpr "MIT OR BSD-3-Clause"+-- False+--+equivalent :: License -> License -> Bool+equivalent a b = exprToLSLic a `LS.equivalent` exprToLSLic b++-------------------------------------------------------------------------------+-- internal+-------------------------------------------------------------------------------++data Lic = Lic !SimpleLicenseExpression !(Maybe LicenseExceptionId)+  deriving (Eq, Ord)++exprToLSLic :: License -> LatticeSyntax Lic+exprToLSLic NONE          = LBound False+exprToLSLic (License lic) = licTo lic++licTo :: LicenseExpression -> LatticeSyntax Lic+licTo (ELicense lic exc) = LVar (Lic lic exc)+licTo (EAnd a b)         = LMeet (licTo a) (licTo b)+licTo (EOr a b)          = LJoin (licTo a) (licTo b)++-- $setup+-- >>> import Distribution.Parsec.Class (simpleParsec)+-- >>> let unsafeParseExpr e = maybe (error $ "invalid: " ++ e) (id :: License -> License) (simpleParsec e)
+ src/Distribution/SPDX/Extra/Internal.hs view
@@ -0,0 +1,142 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DeriveFoldable #-}+{-# LANGUAGE DeriveTraversable #-}+{-# LANGUAGE DeriveDataTypeable #-}+-- |+--+-- Inspired by <http://www.well-typed.com/blog/2014/12/simple-smt-solver/ Simple SMT Solver>.+--+-- In future this module will probably be moved into separate package.+module Distribution.SPDX.Extra.Internal+  (LatticeSyntax(..), dual, freeVars, equivalent, preorder, satisfiable) where++import Control.Applicative+import Control.Monad+import Control.Monad.Trans.State.Strict+import Data.Data+import Data.Foldable+import Data.Traversable+import Prelude hiding (all, or)++import qualified Data.Map.Strict as Map++data LatticeSyntax a = LVar a+                     | LBound Bool+                     | LJoin (LatticeSyntax a) (LatticeSyntax a)+                     | LMeet (LatticeSyntax a) (LatticeSyntax a)+  deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable, Typeable, Data)++instance Applicative LatticeSyntax where+  pure  = return+  (<*>) = ap++instance Monad LatticeSyntax where+  return = LVar+  LVar x    >>= f = f x+  LBound b  >>= _ = LBound b+  LJoin a b >>= f = LJoin (a >>= f) (b >>= f)+  LMeet a b >>= f = LMeet (a >>= f) (b >>= f)++freeVars :: LatticeSyntax a -> [a]+freeVars = toList++dual :: LatticeSyntax a -> LatticeSyntax a+dual (LVar v) = LVar v+dual (LBound t) = LBound $ not t+dual (LJoin a b) = LMeet (dual a) (dual b)+dual (LMeet a b) = LJoin (dual a) (dual b)++-- | Test for equivalence.+--+-- >>> equivalent (LMeet (LVar 'a') (LVar 'b')) (LMeet (LVar 'b') (LVar 'a'))+-- True+--+-- >>> equivalent (LVar 'a') (LMeet (LVar 'a') (LVar 'a'))+-- True+--+-- >>> equivalent (LMeet (LVar 'a') (LVar 'b')) (LMeet (LVar 'b') (LVar 'b'))+-- False+equivalent :: Ord a => LatticeSyntax a -> LatticeSyntax a -> Bool+equivalent a b = all (uncurry (==)) . runEval $ p+  where p = (,) <$> evalLattice a <*> evalLattice b++-- | Test for preorder.+--+-- @ a ≤ b ⇔ a ∨ b ≡ b ⇔ a ≡ a ∧ b @+--+-- >>> preorder (LVar 'a' `LMeet` LVar 'b') (LVar 'a')+-- True+--+-- >>> preorder (LVar 'a') (LVar 'a' `LMeet` LVar 'b')+-- False+preorder :: Ord a => LatticeSyntax a -> LatticeSyntax a -> Bool+preorder a b = (a `LJoin` b) `equivalent` b++-- | Return `True` if for some variable assigment expression evaluates to `True`.+satisfiable :: Ord a => LatticeSyntax a -> Bool+satisfiable = or . runEval . evalLattice++newtype Eval v a = Eval { unEval :: StateT (Map.Map v Bool) [] a }++instance Functor (Eval v) where+  fmap = liftM++instance Applicative (Eval v) where+  pure = return+  (<*>) = ap++instance Alternative (Eval v) where+  empty = mzero+  (<|>) = mplus++instance Monad (Eval v) where+  return = Eval . return+  Eval m >>= k = Eval $ m >>= unEval . k++instance MonadPlus (Eval v) where+  mzero = Eval mzero+  Eval a `mplus` Eval b = Eval $ a `mplus` b++runEval :: Eval v a -> [a]+runEval act = evalStateT (unEval act) Map.empty++evalLattice :: Ord v => LatticeSyntax v -> Eval v Bool+evalLattice (LVar v)    = guess v+evalLattice (LBound b)  = return b+evalLattice (LJoin a b) = evalLattice a ||^ evalLattice b+evalLattice (LMeet a b) = evalLattice a &&^ evalLattice b++guess :: Ord v => v -> Eval v Bool+guess v = Eval $ do+  st <- get+  let remember b = put (Map.insert v b st) >> return b+  case Map.lookup v st of+    Just b  -> return b+    Nothing -> remember True <|> remember False++-- From Control.Monad.Extra of extra++-- | Like @if@, but where the test can be monadic.+ifM :: Monad m => m Bool -> m a -> m a -> m a+ifM b t f = do b' <- b; if b' then t else f++-- | The lazy '||' operator lifted to a monad. If the first+--   argument evaluates to 'True' the second argument will not+--   be evaluated.+--+-- > Just True  ||^ undefined  == Just True+-- > Just False ||^ Just True  == Just True+-- > Just False ||^ Just False == Just False+(||^) :: Monad m => m Bool -> m Bool -> m Bool+(||^) a b = ifM a (return True) b++-- | The lazy '&&' operator lifted to a monad. If the first+--   argument evaluates to 'False' the second argument will not+--   be evaluated.+--+-- > Just False &&^ undefined  == Just False+-- > Just True  &&^ Just True  == Just True+-- > Just True  &&^ Just False == Just False+(&&^) :: Monad m => m Bool -> m Bool -> m Bool+(&&^) a b = ifM a b (return False)
tests/Generators.hs view
@@ -11,20 +11,17 @@  import           Test.Tasty.QuickCheck as QC -import           Data.SPDX-import           Data.SPDX.LatticeSyntax (LatticeSyntax(..))+import           Distribution.SPDX+import           Distribution.SPDX.Extra.Internal (LatticeSyntax(..))  licenseIdGen :: Gen LicenseId-licenseIdGen = elements licenseIdentifiers+licenseIdGen = elements $ licenseIdList LicenseListVersion_3_2  licenseExceptionGen :: Gen LicenseExceptionId-licenseExceptionGen = elements licenseExceptions--maybeGen :: Gen a -> Gen (Maybe a)-maybeGen g = oneof [ pure Nothing, Just <$> g]+licenseExceptionGen = elements $ licenseExceptionIdList LicenseListVersion_3_2  licenseRefGen :: Gen LicenseRef-licenseRefGen = LicenseRef <$> maybeGen idStringGen <*> idStringGen+licenseRefGen = mkLicenseRef' <$> liftArbitrary idStringGen <*> idStringGen  idStringGen :: Gen String idStringGen = elements ["foo", "bar", "baz", "AllRightsReserved"]@@ -39,29 +36,32 @@                       ]           where gen' = gen (n `div` 2) -mkExprGen :: Gen LicenseExpression -> Gen LicenseExpression-mkExprGen licGen = sized gen-  where gen 0 = licGen-        gen n = oneof [ licGen-                      , EDisjunction <$> gen' <*> gen'-                      , EConjunction <$> gen' <*> gen'-                      ]-          where gen' = gen (n `div` 2)+mkExprGen :: Gen LicenseExpression -> Gen License+mkExprGen licGen = License <$> sized gen where+    gen 0 = licGen+    gen n = oneof [ licGen+                  , EOr <$> gen' <*> gen'+                  , EAnd <$> gen' <*> gen'+                  ]+      where gen' = gen (n `div` 2) -exprGen :: Gen LicenseExpression-exprGen = mkExprGen $ ELicense <$> arbitrary <*> (Right <$> licenseIdGen) <*> (pure Nothing)+exprGen :: Gen License+exprGen = mkExprGen $ ELicense <$> simpleLicenseExprGen <*> pure Nothing  -- | 'exprGen' which contains also LicenseRefs and exceptions-exprGen' :: Gen LicenseExpression-exprGen' = mkExprGen $ ELicense <$> arbitrary <*> eitherLicenseIdRefGen <*> maybeGen licenseExceptionGen+exprGen' :: Gen License+exprGen' = mkExprGen $ ELicense <$> simpleLicenseExprGen <*> liftArbitrary licenseExceptionGen -eitherLicenseIdRefGen :: Gen (Either LicenseRef LicenseId)-eitherLicenseIdRefGen = oneof [Right <$> licenseIdGen, Left <$> licenseRefGen]+simpleLicenseExprGen :: Gen SimpleLicenseExpression+simpleLicenseExprGen = oneof [ELicenseId <$> licenseIdGen, ELicenseRef <$> licenseRefGen] -exprShrink :: LicenseExpression -> [LicenseExpression]-exprShrink (ELicense _ _ _)   = []-exprShrink (EDisjunction a b) = a : b : ((a `EDisjunction`) <$> exprShrink b) ++ ((`EDisjunction` b) <$> exprShrink a)-exprShrink (EConjunction a b) = a : b : ((a `EConjunction`) <$> exprShrink b) ++ ((`EConjunction` b) <$> exprShrink a)+exprShrink :: License -> [License]+exprShrink NONE        = []+exprShrink (License e) = map License (go e) where+    go :: LicenseExpression -> [LicenseExpression]+    go (ELicense _ _) = []+    go (EOr a b)      = a : b : map (uncurry EOr)  (liftShrink2 go go (a, b))+    go (EAnd a b)     = a : b : map (uncurry EAnd) (liftShrink2 go go (a, b))  scaleGen :: (Int -> Int) -> Gen a -> Gen a scaleGen f g = sized (\n -> resize (f n) g)
tests/Tests.hs view
@@ -1,14 +1,18 @@ module Main (main) where -import           Data.List-import           Test.Tasty-import           Test.Tasty.QuickCheck as QC--import           Data.SPDX-import           Data.SPDX.LatticeSyntax (LatticeSyntax(..))-import qualified Data.SPDX.LatticeSyntax as LS+import Data.Maybe                       (isJust)+import Distribution.Parsec.Class+import Distribution.Pretty+import Distribution.SPDX+import Distribution.SPDX.Extra+import Distribution.SPDX.Extra.Internal (LatticeSyntax (..))+import Generators+import Prelude ()+import Prelude.Compat+import Test.Tasty+import Test.Tasty.QuickCheck            as QC -import           Generators+import qualified Distribution.SPDX.Extra.Internal as LS  main :: IO () main = defaultMain tests@@ -20,10 +24,10 @@ properties = testGroup "Properties" [qcProps]  up :: String -> LicenseExpression-up = unsafeParseExpr+up = maybe (error "invalid expr") id . simpleParsec  valid :: String -> Bool-valid = (==1) . length . parseExpression+valid s = isJust (simpleParsec s :: Maybe License)  validExpr :: TestName -> TestTree validExpr str = QC.testProperty str $ once $ property $ valid str@@ -34,19 +38,19 @@ units :: TestTree units = testGroup "Unit tests" [ simpleUnits                                , compositeUnits-                               , rangeUnit                                ] + -- | Like `equivalent`, but prints a counterexample when it fails.-equivalentProp :: [LicenseExpression] -> [LicenseExpression] -> Property-equivalentProp x y =-  counterexample (show x ++ " /= " ++ show y) $ length x == length y && (and $ zipWith equivalent x y)+equivalentProp :: Maybe License -> Maybe License -> Property+equivalentProp x y = counterexample (show x ++ " /= " ++ show y) $+    length x == length y && (and $ equivalent <$> x <*> y)  simpleUnits :: TestTree simpleUnits = testGroup "Simple License Expressions"   [ invalidExpr "Invalid-Identifier"-  , validExpr "GPL-2.0"-  , validExpr "GPL-2.0+"+  , validExpr "GPL-2.0-only"+  , validExpr "GPL-2.0-or-later"   , validExpr "LicenseRef-23"   , validExpr "LicenseRef-MIT-Style-1"   , validExpr "DocumentRef-spdx-tool-1.2:LicenseRef-MIT-Style-2"@@ -54,18 +58,15 @@  compositeUnits :: TestTree compositeUnits = testGroup "Composite License Expressions"-  [ validExpr "LGPL-2.1 OR MIT"-  , validExpr "LGPL-2.1 OR MIT OR BSD-3-Clause"-  , validExpr "LGPL-2.1 AND MIT"-  , validExpr "LGPL-2.1 AND MIT AND BSD-2-Clause"-  , validExpr "GPL-2.0+ WITH Bison-exception-2.2"+  [ validExpr "LGPL-2.1-only OR MIT"+  , validExpr "LGPL-2.1-only OR MIT OR BSD-3-Clause"+  , validExpr "LGPL-2.1-only AND MIT"+  , validExpr "LGPL-2.1-only AND MIT AND BSD-2-Clause"+  , validExpr "GPL-2.0-or-later WITH Bison-exception-2.2"   , QC.testProperty "Order of Precedence and Parentheses" $ once $ property $-    up "LGPL-2.1 OR BSD-3-Clause AND MIT" == EDisjunction (up "LGPL-2.1") (EConjunction (up "BSD-3-Clause") (up "MIT"))+    up "LGPL-2.1-only OR BSD-3-Clause AND MIT" == EOr (up "LGPL-2.1-only") (EAnd (up "BSD-3-Clause") (up "MIT"))   ] -rangeUnit :: TestTree-rangeUnit = QC.testProperty "calculated license ranges" $ once $ sort (map (map getLicenseId) licenseRanges) === sort ranges- lsProps :: TestTree lsProps = testGroup "LatticeSyntax"   [ QC.testProperty "a ≤ b ⇔ a ∨ b ≡ b ⇔ a ≡ a ∧ b" $ forAll latticeSyntaxGen $ \a -> forAll latticeSyntaxGen $ \b ->@@ -76,77 +77,20 @@   , QC.testProperty "preorder reflexive" $ forAll latticeSyntaxGen $ \a -> a `LS.preorder` a   ] -osiLicenseIds :: [LicenseId]-osiLicenseIds = filter isOsiApproved licenseIdentifiers--osiLicenseExpr :: LicenseExpression-osiLicenseExpr = foldr1 EConjunction $ map (\l -> ELicense False (Right l) Nothing) osiLicenseIds--isOsiApprovedExpr :: LicenseExpression -> Bool-isOsiApprovedExpr (ELicense _ (Left _) _) = False-isOsiApprovedExpr (ELicense _ _ (Just _)) = False-isOsiApprovedExpr (ELicense False (Right e) Nothing) = isOsiApproved e-isOsiApprovedExpr (ELicense True (Right e2) Nothing) = any isOsiApproved $ lookupLicenseRange e2-isOsiApprovedExpr (EConjunction e1 e2) = isOsiApprovedExpr e1 && isOsiApprovedExpr e2-isOsiApprovedExpr (EDisjunction e1 e2) = isOsiApprovedExpr e1 || isOsiApprovedExpr e2--isOsiApprovedExpr' :: LicenseExpression -> Bool-isOsiApprovedExpr' e = e `satisfies` osiLicenseExpr- qcProps :: TestTree qcProps = testGroup "By Quickcheck"-  [ QC.testProperty "licence identifiers are valid licenses" $ forAll licenseIdGen $ valid . getLicenseId-  , QC.testProperty "satisfies osi checked" $ forAll (scaleGen (`div` 3) exprGen) $-      \e -> isOsiApprovedExpr e == isOsiApprovedExpr' e -- Skip+  [ QC.testProperty "licence identifiers are valid licenses" $ forAll licenseIdGen $ valid . prettyShow   , lsProps   , parsePrettyProps   ]  parsePrettyProps :: TestTree parsePrettyProps = testGroup "parse . pretty"-  [ QC.testProperty "LicenseId" $ forAll licenseIdGen $ \i -> mkLicenseId (prettyLicenseId i) === Just i-  , QC.testProperty "LicenseExpression"  $ forAllShrink (scaleGen (`div` 3) exprGen)  exprShrink $ \e -> parseExpression (prettyLicenseExpression e) `equivalentProp` [e]-  , QC.testProperty "LicenseExpression'" $ forAllShrink (scaleGen (`div` 3) exprGen') exprShrink $ \e -> parseExpression (prettyLicenseExpression e) `equivalentProp` [e]+  [ QC.testProperty "LicenseId" $ forAll licenseIdGen $ \i -> mkLicenseId LicenseListVersion_3_2 (prettyShow i) === Just i+  , QC.testProperty "LicenseExpression"  $ forAllShrink (scaleGen (`div` 3) exprGen)  exprShrink $ \e ->+      let p = prettyShow e+      in counterexample p $ simpleParsec p `equivalentProp` Just e+  , QC.testProperty "LicenseExpression'" $ forAllShrink (scaleGen (`div` 3) exprGen') exprShrink $ \e ->+      let p = prettyShow e+      in counterexample p $ simpleParsec p `equivalentProp` Just e   ]--ranges :: [[String]]-ranges =-    [ ["AFL-1.1","AFL-1.2","AFL-2.0","AFL-2.1","AFL-3.0"]-    , ["AGPL-1.0","AGPL-3.0"]-    , ["APSL-1.0","APSL-1.1","APSL-1.2","APSL-2.0"]-    , ["Apache-1.0","Apache-1.1","Apache-2.0"]-    , ["Artistic-1.0","Artistic-2.0"]-    , ["BitTorrent-1.0","BitTorrent-1.1"]-    , ["CC-BY-1.0","CC-BY-2.0","CC-BY-2.5","CC-BY-3.0","CC-BY-4.0"]-    , ["CC-BY-NC-1.0","CC-BY-NC-2.0","CC-BY-NC-2.5","CC-BY-NC-3.0","CC-BY-NC-4.0"]-    , ["CC-BY-NC-ND-1.0","CC-BY-NC-ND-2.0","CC-BY-NC-ND-2.5","CC-BY-NC-ND-3.0","CC-BY-NC-ND-4.0"]-    , ["CC-BY-NC-SA-1.0","CC-BY-NC-SA-2.0","CC-BY-NC-SA-2.5","CC-BY-NC-SA-3.0","CC-BY-NC-SA-4.0"]-    , ["CC-BY-ND-1.0","CC-BY-ND-2.0","CC-BY-ND-2.5","CC-BY-ND-3.0","CC-BY-ND-4.0"]-    , ["CC-BY-SA-1.0","CC-BY-SA-2.0","CC-BY-SA-2.5","CC-BY-SA-3.0","CC-BY-SA-4.0"]-    , ["CDDL-1.0","CDDL-1.1"]-    , ["CECILL-1.0","CECILL-1.1","CECILL-2.0","CECILL-2.1"]-    , ["ECL-1.0","ECL-2.0"]-    , ["EFL-1.0","EFL-2.0"]-    , ["EUPL-1.0","EUPL-1.1"]-    , ["GFDL-1.1","GFDL-1.2","GFDL-1.3"]-    , ["GPL-1.0","GPL-2.0","GPL-3.0"]-    , ["LAL-1.2","LAL-1.3"]-    , ["LGPL-2.0","LGPL-2.1","LGPL-3.0"]-    , ["LPL-1.0","LPL-1.02"]-    , ["LPPL-1.0","LPPL-1.1","LPPL-1.2","LPPL-1.3a","LPPL-1.3c"]-    , ["MPL-1.0","MPL-1.1","MPL-2.0"]-    , ["NPL-1.0","NPL-1.1"]-    , ["OFL-1.0","OFL-1.1"]-    , ["OLDAP-1.1","OLDAP-1.2","OLDAP-1.3","OLDAP-1.4","OLDAP-2.0","OLDAP-2.0.1","OLDAP-2.1","OLDAP-2.2","OLDAP-2.2.1","OLDAP-2.2.2","OLDAP-2.3","OLDAP-2.4","OLDAP-2.5","OLDAP-2.6","OLDAP-2.7","OLDAP-2.8"]-    , ["OSL-1.0","OSL-1.1","OSL-2.0","OSL-2.1","OSL-3.0"]-    , ["PHP-3.0","PHP-3.01"]-    , ["RPL-1.1","RPL-1.5"]-    , ["SGI-B-1.0","SGI-B-1.1","SGI-B-2.0"]-    , ["Spencer-86","Spencer-94","Spencer-99"]-    , ["Unicode-DFS-2015","Unicode-DFS-2016"]-    , ["W3C-19980720","W3C-20150513"]-    , ["YPL-1.0","YPL-1.1"]-    , ["ZPL-1.1","ZPL-2.0","ZPL-2.1"]-    , ["Zimbra-1.3","Zimbra-1.4"]-    , ["bzip2-1.0.5","bzip2-1.0.6"]-    ]