module MagicHaskeller.IOGenerator(module MagicHaskeller.IOGenerator, NearEq((~=))) where
#ifdef TFRANDOM
import System.Random.TF.Gen
import System.Random.TF.Instances
#else
import System.Random
#endif
import MagicHaskeller.MyCheck
import Data.List(sort, group, sortBy, groupBy, nubBy, intersperse)
import Data.Function(on)
import Data.Char(isAlphaNum)
import MagicHaskeller.FastRatio
import MagicHaskeller.LibTH(everythingF, pgfull, postprocess)
import MagicHaskeller.ExpToHtml(pprnn, annotateString, Language(..))
import Language.Haskell.TH(pprint, Exp)
import Data.Typeable
import Text.Html(stringToHtmlString)
import MagicHaskeller.NearEq(NearEq((~=)))
#ifdef TFRANDOM
arbitraries :: Arbitrary a => [a]
arbitraries = arbs 4 (seedTFGen (12279932681387497184,218462391894233257,1625759680792809304,12756118543158863164))
arbs :: Arbitrary a => Int -> TFGen -> [a]
arbs n stdgen = case map (splitn stdgen 8) [0..255] of
g0:gs -> map (f n) gs ++ arbs n g0
where Gen f = arbitrary
#else
arbitraries :: Arbitrary a => [a]
arbitraries = arbs 4 (mkStdGen 1)
arbs :: Arbitrary a => Int -> StdGen -> [a]
arbs n stdgen = case split stdgen of
(g0,g1) -> f n g0 : arbs n g1
where Gen f = arbitrary
#endif
showIOPairsHTML :: String -> [ShownIOPair] -> String
showIOPairsHTML = showIOPairsHTML' (const showIOPairHTML)
showIOPairsWithFormsHTML :: String
-> String
-> String -> [ShownIOPair] -> String
showIOPairsWithFormsHTML mypath predicate
= let beginForm = "<FORM ACTION='"++mypath++"' METHOD=GET> <INPUT TYPE=HIDDEN NAME='predicate' VALUE='"++concatMap escapeQuote predicate ++"'> <INPUT TYPE=HIDDEN NAME='inputs' VALUE='"
in showIOPairsHTML' (showIOPairWithFormHTML beginForm)
showIOPairsHTML' :: (Int -> ShownIOPair -> String) -> String -> [ShownIOPair] -> String
showIOPairsHTML' shower funname iopairs
= concat $ map (("<tr align=left cellspacing=20><td><font size=1 color='#888888'>&&</font> </td><td>"++) . (funname++) . shower boxSize) iopairs
where boxSize = maximum $ 20 : map length (snd $ unzip iopairs)
nubOn f = map snd . nubBy ((==) `on` fst) . map (\x -> (f x, x))
nubSortedOn f = map snd . nubSortedOn' fst . map (\x -> (f x, x))
nubSortedOn' f = map head . groupBy ((==) `on` f) . sortBy (compare `on` f)
type ShownIOPair = ([AnnShowS], String)
iopairToInputs :: ShownIOPair -> [String]
iopairToInputs (funs,_) = map assToString funs
assToString :: AnnShowS -> String
assToString fun = fun id ""
type AnnShowS = (String->String)
-> String -> String
showIOPairHTML :: ShownIOPair -> String
showIOPairHTML (args,ret) = foldr (\arg str -> " </td><td> " ++ arg (annotateString LHaskell) str) (" </td><td> ~= </td><td> "++ret++ " </td></tr>") args
showIOPairWithFormHTML begin boxSize pair@(args,ret) = showIOPairHTML (args, mkForm begin boxSize pair)
mkForm :: String
-> Int
-> ShownIOPair
-> String
mkForm begin boxSize (args,ret)
= begin ++ concatMap escapeQuote (showsInputs args "") ++ "'> <INPUT TYPE=TEXT NAME='output' VALUE='"++concatMap escapeQuote ret ++ "' SIZE="++show boxSize ++"> <INPUT TYPE=SUBMIT VALUE='Narrow search'> </FORM>"
showsInputs args = \s -> foldr (\arg str -> ' ' : arg id str) s args
escapeQuote '\'' = "'"
escapeQuote c = [c]
class IOGenerator a where
generateIOPairs :: a -> [ShownIOPair]
instance (IOGenerator r) => IOGenerator (Int->r) where
generateIOPairs = generateIOPairsLitNum integrals
instance (IOGenerator r) => IOGenerator (Integer->r) where
generateIOPairs = generateIOPairsLitNum integrals
instance (IOGenerator r) => IOGenerator (Float->r) where
generateIOPairs = generateIOPairsLitNum arbitraries
instance (IOGenerator r) => IOGenerator (Double->r) where
generateIOPairs = generateIOPairsLitNum arbitraries
generateIOPairsLitNum :: (Num a, Ord a, Show a, IOGenerator b) =>
[a] -> (a -> b) -> [ShownIOPair]
generateIOPairsLitNum rs f = [ (const (showParen (a<0) (shows a)) : args, ret) | a <- uniqSort $ take 4 rs, (args,ret) <- generateIOPairs (f a) ]
integrals :: Integral i => [i]
integrals = concat $ zipWith (\a b -> [a,b]) [0,1..] [1..]
instance (IOGenerator r) => IOGenerator (()->r) where
generateIOPairs f = generateIOPairsFun False f
instance (IOGenerator r) => IOGenerator (Bool->r) where
generateIOPairs f = generateIOPairsFun False f
instance (IOGenerator r) => IOGenerator (Ordering->r) where
generateIOPairs f = generateIOPairsFun False f
instance (IOGenerator r) => IOGenerator (Char->r) where
generateIOPairs f = [ (const (stringToHtmlString (show a) ++) : args, ret) | a <- " \nAb.", (args,ret) <- generateIOPairs (f a) ]
instance (IOGenerator r) => IOGenerator (String->r) where
generateIOPairs f = [ (const (shows a) : args, ret) | a <- sortBy (compare `on` length) $ uniqSort $ "" : "12345" : "Abc\nd Ef" : take 2 arbitraries,
(args, ret) <- generateIOPairs (f a) ]
instance (ShowArbitrary a, IOGenerator r) => IOGenerator (a->r) where
generateIOPairs = mhGenerateIOPairs
mhGenerateIOPairs :: (ShowArbitrary a, IOGenerator b) =>
(a -> b) -> [ShownIOPair]
mhGenerateIOPairs f = [ (astr : args, ret)
| (astr, a) <- take 5 $ nubOn (assToString . fst) showArbitraries,
(args, ret) <- generateIOPairs (f a) ]
class ShowArbitrary a where
showArbitraries :: [(AnnShowS, a)]
sas :: (Show a) => (a->Bool) -> [a] -> [(AnnShowS, a)]
sas cond xs = [ (const $ showParen (cond x) (shows x), x) | x <- xs ]
sasNum :: (Show a, Arbitrary a, Num a, Ord a) => [(AnnShowS, a)]
sasNum = sas (<0) arbitraries
sasFalse :: (Show a) => [a] -> [(AnnShowS, a)]
sasFalse = sas (const False)
sasIntegral :: (Show a, Arbitrary a, Integral a, Ord a) => [(AnnShowS, a)]
sasIntegral = sas (<0) [0,1] ++
drop 2 sasNum
instance ShowArbitrary () where
showArbitraries = repeat (const ("()"++),())
instance ShowArbitrary Bool where
showArbitraries = sasFalse $ [False, True] ++ arbitraries
instance ShowArbitrary Int where
showArbitraries = sasIntegral
instance ShowArbitrary Integer where
showArbitraries = sasIntegral
instance ShowArbitrary Float where
showArbitraries = sasNum
instance ShowArbitrary Double where
showArbitraries = sasNum
instance ShowArbitrary Char where
showArbitraries = sasFalse $ " \nAb."++ drop 5 arbitraries
instance ShowArbitrary Ordering where
showArbitraries = sasFalse $ [LT,EQ,GT] ++ arbitraries
instance (Integral i, Random i, Show i) => ShowArbitrary (Ratio i) where
showArbitraries = sas (const True) arbitraries
instance ShowArbitrary a => ShowArbitrary (Maybe a) where
showArbitraries = (const ("Nothing"++), Nothing) : map (mapSA "Just " Just) showArbitraries
instance (ShowArbitrary a, ShowArbitrary b) => ShowArbitrary (Either a b) where
showArbitraries = zipWith3 (\b l r -> if b then mapSA "Left " Left l else mapSA "Right " Right r) arbitraries showArbitraries showArbitraries
mapSA str fun (f,x) = (\annotater -> showParen True ((str++) . f annotater), fun x)
instance (ShowArbitrary a, ShowArbitrary b) => ShowArbitrary (a, b) where
showArbitraries = zipWith (\(f1,x1) (f2,x2) -> (\annotater -> ('(':) . f1 annotater . (',':) . f2 annotater . (')':), (x1,x2)))
(skip 1 showArbitraries)
(skip 1 $ drop 1 showArbitraries)
instance (ShowArbitrary a, ShowArbitrary b, ShowArbitrary c) => ShowArbitrary (a, b, c) where
showArbitraries = zipWith3 (\(f1,x1) (f2,x2) (f3,x3) -> (\annotater -> ('(':) . f1 annotater . (',':) . f2 annotater . (',':) . f3 annotater . (')':), (x1,x2,x3)))
(skip 2 showArbitraries)
(skip 2 $ drop 1 showArbitraries)
(skip 2 $ drop 2 showArbitraries)
skip n (x:xs) = x : skip n (drop n xs)
instance ShowArbitrary a => ShowArbitrary [a] where
showArbitraries = map cvt $ chopBy arbitraries showArbitraries
chopBy :: [Int] -> [a] -> [[a]]
chopBy _ [] = []
chopBy is xs = cb is $ cycle xs
where cb (i:is) xs | i < 0 = cb is xs
| otherwise = case splitAt i xs of (tk,dr) -> tk : cb is dr
cvt :: [(AnnShowS,a)] -> (AnnShowS, [a])
cvt ts = case unzip ts of (fs, xs) -> (showsList fs, xs)
showsList fs@(f:_) | head (f id "") == '\''
= const $ shows (map (\fun -> read $ fun id "") fs :: String)
showsList fs = \annotater -> ('[':) . foldr (.) (']':) (intersperse (',':) $ map ($ annotater) fs)
instance (Typeable a, Typeable b) => ShowArbitrary (a->b) where
showArbitraries = map (\(e,a) -> (\annotater -> (annotater (pprnn (postprocess e)) ++) , a)) $ concat $ take 5 $ everythingF pgfull True
generateIOPairsFun :: (Ord a, Show a, Arbitrary a, IOGenerator b) => Bool -> (a->b) -> [ShownIOPair]
generateIOPairsFun b f = [ (const (showParen b (shows a)) : args, ret)
| a <- uniqSort $ take 5 arbitraries
, (args, ret) <- generateIOPairs (f a) ]
instance Show a => IOGenerator a where
generateIOPairs x = [([], stringToHtmlString $ show x)]
uniqSort :: Ord a => [a] -> [a]
uniqSort = map head . group . sort