diff --git a/semantic.cabal b/semantic.cabal index d2b02b695..30c7a2374 100644 --- a/semantic.cabal +++ b/semantic.cabal @@ -38,8 +38,8 @@ library -- Control flow , Control.Effect -- Effects used for program analysis - , Control.Monad.Effect.Fresh - , Control.Monad.Effect.NonDet + , Control.Effect.Fresh + , Control.Effect.NonDet -- Datatypes for abstract interpretation , Data.Abstract.Address , Data.Abstract.Cache @@ -257,6 +257,16 @@ test-suite test default-language: Haskell2010 default-extensions: DeriveFunctor, DeriveGeneric, FlexibleContexts, FlexibleInstances, OverloadedStrings, RecordWildCards +test-suite doctests + type: exitcode-stdio-1.0 + hs-source-dirs: test + main-is: Doctests.hs + default-language: Haskell2010 + ghc-options: -dynamic -threaded -j + build-depends: base + , doctest + , QuickCheck + benchmark evaluation hs-source-dirs: bench type: exitcode-stdio-1.0 diff --git a/src/Analysis/Abstract/Evaluating.hs b/src/Analysis/Abstract/Evaluating.hs index 8accb44d6..2564d5cf9 100644 --- a/src/Analysis/Abstract/Evaluating.hs +++ b/src/Analysis/Abstract/Evaluating.hs @@ -8,8 +8,6 @@ module Analysis.Abstract.Evaluating import Control.Abstract.Evaluator import Control.Monad.Effect hiding (run) import Control.Monad.Effect.Fail -import Control.Monad.Effect.Fresh -import Control.Monad.Effect.NonDet import Control.Monad.Effect.Reader import Control.Monad.Effect.State import Data.Abstract.Configuration diff --git a/src/Assigning/Assignment.hs b/src/Assigning/Assignment.hs index 2beab85d2..ec727ae23 100644 --- a/src/Assigning/Assignment.hs +++ b/src/Assigning/Assignment.hs @@ -37,9 +37,7 @@ -- -- Assignments can represent alternatives as either committed or uncommitted choices, both written with '<|>'. “Committed” in this context means that a failure in one of the alternatives will not result in backtracking followed by an attempt of one of the other alternatives; thus, committed choice is more efficient. (By the same token, it enables much better error messages since backtracking erases most of the relevant context.) Committed choices are constructed via the following rules: -- --- 1. 'empty' is dropped from choices: --- prop> empty <|> a = a -- empty is the left-identity of <|> --- prop> a <|> empty = a -- empty is the right-identity of <|> +-- 1. 'empty' is dropped from choices. -- -- 2. 'symbol' rules construct a committed choice (with only a single alternative). -- diff --git a/src/Control/Abstract/Analysis.hs b/src/Control/Abstract/Analysis.hs index 051215d6f..452ddf991 100644 --- a/src/Control/Abstract/Analysis.hs +++ b/src/Control/Abstract/Analysis.hs @@ -14,10 +14,10 @@ module Control.Abstract.Analysis import Control.Abstract.Evaluator as X import Control.Effect as X +import Control.Effect.Fresh as X +import Control.Effect.NonDet as X import qualified Control.Monad.Effect as Effect import Control.Monad.Effect.Fail as X -import Control.Monad.Effect.Fresh as X -import Control.Monad.Effect.NonDet as X import Control.Monad.Effect.Reader as X import Control.Monad.Effect.State as X import Data.Abstract.Environment diff --git a/src/Control/Abstract/Value.hs b/src/Control/Abstract/Value.hs index 3fa4af8eb..73295cd78 100644 --- a/src/Control/Abstract/Value.hs +++ b/src/Control/Abstract/Value.hs @@ -80,7 +80,7 @@ class (Monad m, Show value) => MonadValue value m where -- | Construct an array of zero or more values. array :: [value] -> m value --- | Extract a 'ByteString' from a given value. + -- | Extract a 'ByteString' from a given value. asString :: value -> m ByteString -- | Eliminate boolean values. TODO: s/boolean/truthy @@ -101,10 +101,10 @@ toBool :: MonadValue value m => value -> m Bool toBool v = ifthenelse v (pure True) (pure False) forLoop :: (MonadEnvironment value m, MonadValue value m) - => m value -- | Initial statement - -> m value -- | Condition - -> m value -- | Increment/stepper - -> m value -- | Body + => m value -- ^ Initial statement + -> m value -- ^ Condition + -> m value -- ^ Increment/stepper + -> m value -- ^ Body -> m value forLoop initial cond step body = do void initial diff --git a/src/Control/Monad/Effect/Fresh.hs b/src/Control/Effect/Fresh.hs similarity index 96% rename from src/Control/Monad/Effect/Fresh.hs rename to src/Control/Effect/Fresh.hs index b90e98073..44262e93e 100644 --- a/src/Control/Monad/Effect/Fresh.hs +++ b/src/Control/Effect/Fresh.hs @@ -1,5 +1,5 @@ {-# LANGUAGE GADTs, MultiParamTypeClasses, TypeOperators, UndecidableInstances #-} -module Control.Monad.Effect.Fresh where +module Control.Effect.Fresh where import Control.Effect import Control.Monad.Effect.Internal diff --git a/src/Control/Monad/Effect/NonDet.hs b/src/Control/Effect/NonDet.hs similarity index 97% rename from src/Control/Monad/Effect/NonDet.hs rename to src/Control/Effect/NonDet.hs index d195031db..34c23f74d 100644 --- a/src/Control/Monad/Effect/NonDet.hs +++ b/src/Control/Effect/NonDet.hs @@ -1,5 +1,5 @@ {-# LANGUAGE TypeFamilies, TypeOperators, UndecidableInstances #-} -module Control.Monad.Effect.NonDet +module Control.Effect.NonDet ( MonadNonDet(..) , NonDetEff ) where diff --git a/src/Data/Range.hs b/src/Data/Range.hs index a5e203310..280303b77 100644 --- a/src/Data/Range.hs +++ b/src/Data/Range.hs @@ -36,6 +36,13 @@ subtractRange range1 range2 = Range (start range1) (end range1 - rangeLength (Ra -- Instances +-- $setup +-- >>> import Test.QuickCheck +-- >>> instance Arbitrary Range where arbitrary = Range <$> arbitrary <*> arbitrary + +-- $ +-- Associativity: +-- prop> \ a b c -> a <> (b <> c) == (a <> b) <> (c :: Range) instance Semigroup Range where Range start1 end1 <> Range start2 end2 = Range (min start1 start2) (max end1 end2) diff --git a/test/Doctests.hs b/test/Doctests.hs new file mode 100644 index 000000000..1fa391e81 --- /dev/null +++ b/test/Doctests.hs @@ -0,0 +1,24 @@ +module Main +( main +) where + +import System.Environment +import Test.DocTest + +main :: IO () +main = do + args <- getArgs + doctest (map ("-X" ++) extensions ++ "-isrc" : "--fast" : if null args then ["src"] else args) + +extensions :: [String] +extensions = + [ "DeriveFoldable" + , "DeriveFunctor" + , "DeriveGeneric" + , "DeriveTraversable" + , "FlexibleContexts" + , "FlexibleInstances" + , "OverloadedStrings" + , "RecordWildCards" + , "StrictData" + ]