File: Generate.hs

package info (click to toggle)
haskell-derive 2.5.16-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 460 kB
  • sloc: haskell: 3,686; makefile: 5
file content (119 lines) | stat: -rw-r--r-- 4,531 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119

module Derive.Generate(generate) where

import Language.Haskell.Exts
import Data.DeriveDSL
import Derive.Utils
import Control.Monad
import Data.Maybe
import System.FilePath
import System.Directory
import Data.Char
import Data.List


evil = words $ "TTypeable Uniplate"

-- generate extra information for each derivation
generate :: IO ()
generate = do
    xs <- getDirectoryContents "Data/Derive"
    xs <- return $ sort [x | x <- xs, takeExtension x == ".hs", x /= "All.hs", takeBaseName x `notElem` evil]
    lis <- mapM generateFile $ map ("Data/Derive" </>) xs
    let names = map dropExtension xs
        n = maximum $ map length names
    writeGenerated "Data/Derive/All.hs" $
        ["import Data.Derive." ++ x ++ replicate (4 + n - length x) ' ' ++ "as D" | x <- names] ++
        ["derivations :: [Derivation]"
        ,"derivations = [make" ++ concat (intersperse ",make" names) ++ "]"]
    writeGenerated "derive.htm" $ ["-->"] ++ lis ++ ["<!--"]
    writeGenerated "derive.cabal" $ map ("        Data.Derive."++) names


-- return the Documentation string
generateFile :: FilePath -> IO String
generateFile file = do
    let name = takeBaseName file
    putStrLn $ "Generating " ++ name
    src <- readSrc file
    when (isJust $ srcExample src) $ do
        let dsl = fromMaybe (error $ "Couldn't derive example for " ++ name) $
                            deriveDSL $ fromJust $ srcExample src
        writeGenerated file $
            [""
            ,"import Data.Derive.DSL.DSL"
            ,"import Data.Derive.Internal.Derivation"
            ,""
            ,"make" ++ name ++ " :: Derivation"
            ] ++ (if srcCustom src then
                ["make" ++ name ++ " = derivationCustomDSL " ++ show name ++ " custom $"]
            else
                ["make" ++ name ++ " = derivationDSL " ++ show name ++ " dsl" ++ name
                ,""
                ,"dsl" ++ name ++ " ="
            ]) ++
            map (replicate 4 ' ' ++) (wrap 66 $ show dsl)


        let inst = dynamicDSL dsl
            instFile = takeDirectory file </> "Instance" </> name <.> "hs"
        b <- doesFileExist instFile
        if not (srcCustom src) && isJust inst then do
            writeGenerated instFile $
                ["{-# LANGUAGE FlexibleInstances, UndecidableInstances, ScopedTypeVariables #-}"] ++
                ["","module Data.Derive.Instance." ++ name ++ " where",""] ++
                (map prettyPrint $ srcImportStd src) ++
                ["import Data.Derive.Internal.Instance",""] ++
                (map prettyPrint $ fromJust inst) ++ [""]
         else when b $
            error $ "Previously generated dynamic instance can not be regenerated, " ++ name

    let imp = listToMaybe $ srcImport src
    return $ concat $
        ["<li>"
        ,"<b><a href='" ++ instUrl name imp ++ "'>" ++ name ++ "</a></b>"] ++
        [" - from the library <a href='" ++ pkgUrl pkg ++ "'>" ++ pkg ++ "</a>" | Just imp <- [imp], let pkg = fromMaybe "base" $ importPkg imp] ++
        ["</li>"]

pkgUrl x = "http://hackage.haskell.org/package/" ++ x

instUrl name Nothing = "http://hackage.haskell.org/packages/archive/derive/latest/doc/html/Data-Derive-" ++ name ++ ".html"
instUrl name (Just x) = "http://hackage.haskell.org/packages/archive/" ++ pkgName ++ "/" ++ pkgVersion ++ "/doc/html/" ++ modu ++ ".html#t%3A" ++ nam
    where
        (a,b) = break (== '-') $ fromMaybe "base" $ importPkg x
        pkgName = a
        pkgVersion = if null b then "latest" else tail b
        modu = reps '.' '-' $ prettyPrint $ importModule x
        nam = case importSpecs x of Just (False,IAbs y:_) -> prettyPrint y ; _ -> name


wrap :: Int -> String -> [String]
wrap n = f . lexemes
    where
        f [] = []
        f (x:xs) = [reverse $ dropWhile isSpace $ reverse $ concat $ x:a] ++ f (dropWhile (all isSpace) b)
            where (a,b) = thisLine (n - length x) xs

        thisLine i [] = ([], [])
        thisLine i (x:xs) | j > i = ([], x:xs)
                          | otherwise = (x:a, b)
            where j = length x
                  (a,b) = thisLine (i - j) xs


lexemes :: String -> [String]
lexemes [] = []
lexemes x = a : lexemes b
    where (a,b) = lexeme x 


lexeme :: String -> (String, String)
lexeme xs@(x:_) | isAlpha x = span isAlpha xs
lexeme ('\"':xs) = let (a,b) = f xs in ('\"':a,b)
    where f ('\\':x:xs) = let (a,b) = f xs in ('\\':x:a,b)
          f ('\"':xs) = ("\"",xs)
          f (x:xs) = let (a,b) = f xs in (x:a,b)
          f [] = ([],[])
lexeme (x:xs) = ([x], xs)