-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathbuild.hs
99 lines (77 loc) · 2.94 KB
/
build.hs
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
{-# LANGUAGE OverloadedStrings #-}
-----------------------------------------------------------------------------
-- |
-- Simple little parser to smoosh together a set of M-lang expressions each
-- defined in a file of their own, into a single M Record statement.
--
-----------------------------------------------------------------------------
module Main where
import System.FilePath
import System.Directory (listDirectory)
import Data.Char (isSpace)
import Data.List (intercalate, isPrefixOf, sort)
--
-- Config
srcPath :: FilePath
srcPath = "./src"
srcExt :: FileExtension
srcExt = ".pq"
outFile :: FilePath
outFile = "./M" ++ srcExt
--
type FileExtension = String
data PQExpression = PQExpression { identifier :: String
, expressionBody :: String
} deriving (Show, Eq)
-- | List all files within a directory that have the specified extension.
lsFiles :: FileExtension -> FilePath -> IO [FilePath]
lsFiles x = fmap (filter hasExt) . files
where
files path = sort <$> listDirectory path
hasExt = (==) x . takeExtension
-- | lsFiles with a relative path rather than file name.
lsFiles' :: FileExtension -> FilePath -> IO [FilePath]
lsFiles' ext dir = fmap (dir </>) <$> lsFiles ext dir
-- | Read a raw expression from a file.
readExpression :: FilePath -> IO PQExpression
readExpression file = do
let name = takeBaseName file
expression <- trim <$> readFile file
pure $ PQExpression name expression
-- | Parse a folder of expression files into a list.
readExpressions :: FilePath -> IO [PQExpression]
readExpressions dir =
lsFiles' srcExt dir >>=
mapM readExpression
-- | Trim the leading and trailing whitespace from a String.
trim :: String -> String
trim = f . f
where f = reverse . dropWhile isSpace
-- | Indent all lines by the specified number of spaces.
indent :: Int -> String -> String
indent n s = init . unlines $ (++) (replicate n ' ') <$> lines s
-- | Render a PQExpression to named statement.
render :: PQExpression -> String
render (PQExpression name body) = header ++ name ++ " = " ++ expression
where
(header, expression) = mapT unlines $ span isHeaderLine $ lines body
mapT f (a, b) = (f a, f b)
isHeaderLine x
| "/*" `isPrefixOf` x = True
| " *" `isPrefixOf` x = True
| otherwise = False
-- | Join collection of expressions into an record statement.
toRecord :: [PQExpression] -> String
toRecord = group . merge . build
where
build = fmap (indent 4 . render)
merge = intercalate ",\n\n"
group x = "[\n" ++ x ++ "\n]"
main :: IO ()
main = do
putStrLn $ "Building lib from components in " ++ srcPath ++ "\n"
header <- readFile $ srcPath </> "_header.txt"
expressions <- readExpressions srcPath
writeFile outFile $ header ++ "\n" ++ toRecord expressions
mapM_ (putStrLn . indent 2) (identifier <$> expressions)
putStrLn "\nDone!"