8 | 8 |
import Data.Text (Text)
|
9 | 9 |
import qualified Data.Text as T
|
10 | 10 |
import qualified Data.Text.IO as T
|
| 11 |
import qualified System.Console.GetOpt as Opt
|
| 12 |
import qualified System.Environment as Sys
|
| 13 |
import qualified System.Exit as Sys
|
| 14 |
import qualified System.IO as Sys
|
11 | 15 |
|
12 | 16 |
data Decl = Decl
|
13 | 17 |
{ dName :: Text
|
|
64 | 68 |
in go (d:ds) ls
|
65 | 69 |
|
66 | 70 |
builtins :: [Text]
|
67 | |
builtins = [ "null", "int", "integer", "real", "text", "blob", "date" ]
|
| 71 |
builtins = [ "null"
|
| 72 |
, "int"
|
| 73 |
, "integer"
|
| 74 |
, "real"
|
| 75 |
, "text"
|
| 76 |
, "bool"
|
| 77 |
, "blob"
|
| 78 |
, "date"
|
| 79 |
]
|
68 | 80 |
|
69 | 81 |
check :: [Decl] -> Either String ()
|
70 | 82 |
check ds =
|
|
89 | 101 |
| t `elem` builtins = T.toUpper t
|
90 | 102 |
| otherwise = "INTEGER"
|
91 | 103 |
|
92 | |
pprint :: Decl -> IO ()
|
93 | |
pprint Decl { dName = n, dFields = fs } = do
|
94 | |
T.putStr "CREATE TABLE IF NOT EXISTS "
|
95 | |
T.putStrLn n
|
96 | |
T.putStrLn " ( id INTEGER PRIMARY KEY ASC"
|
| 104 |
pprint :: Decl -> Sys.Handle -> IO ()
|
| 105 |
pprint Decl { dName = n, dFields = fs } h = do
|
| 106 |
T.hPutStr h "CREATE TABLE IF NOT EXISTS "
|
| 107 |
T.hPutStrLn h n
|
| 108 |
T.hPutStrLn h " ( id INTEGER PRIMARY KEY ASC"
|
97 | 109 |
mapM_ printField fs
|
98 | 110 |
mapM_ printForeign fs
|
99 | |
T.putStrLn " );"
|
| 111 |
T.hPutStrLn h " );"
|
100 | 112 |
where printField Field { fName = f
|
101 | 113 |
, fType = t
|
102 | 114 |
, fNull = l
|
103 | 115 |
, fUniq = u
|
104 | 116 |
, fDefault = d
|
105 | 117 |
} = do
|
106 | |
T.putStr " , "
|
107 | |
T.putStr f
|
108 | |
T.putStr " "
|
109 | |
T.putStr (typeName t)
|
| 118 |
T.hPutStr h " , "
|
| 119 |
T.hPutStr h f
|
| 120 |
T.hPutStr h " "
|
| 121 |
T.hPutStr h (typeName t)
|
110 | 122 |
when (not l) $
|
111 | |
T.putStr " NOT NULL"
|
| 123 |
T.hPutStr h " NOT NULL"
|
112 | 124 |
when u $
|
113 | |
T.putStr " UNIQUE"
|
| 125 |
T.hPutStr h " UNIQUE"
|
114 | 126 |
case d of
|
115 | 127 |
Nothing -> return ()
|
116 | |
Just dv -> T.putStr (" DEFAULT " <> dv)
|
117 | |
T.putStrLn ""
|
| 128 |
Just dv -> T.hPutStr h (" DEFAULT " <> dv)
|
| 129 |
T.hPutStrLn h ""
|
118 | 130 |
printForeign Field { fName = f, fType = t }
|
119 | 131 |
| t `elem` builtins = return ()
|
120 | 132 |
| otherwise = do
|
121 | |
T.putStr " , FOREIGN KEY("
|
122 | |
T.putStr f
|
123 | |
T.putStr ") REFERENCES "
|
124 | |
T.putStr t
|
125 | |
T.putStrLn "(id)"
|
| 133 |
T.hPutStr h " , FOREIGN KEY("
|
| 134 |
T.hPutStr h f
|
| 135 |
T.hPutStr h ") REFERENCES "
|
| 136 |
T.hPutStr h t
|
| 137 |
T.hPutStrLn h "(id)"
|
126 | 138 |
|
127 | 139 |
rev :: [Decl] -> [Decl]
|
128 | 140 |
rev ds = reverse [ d { dFields = reverse (dFields d) } | d <- ds ]
|
129 | 141 |
|
| 142 |
-- *
|
| 143 |
|
| 144 |
data Options = Options
|
| 145 |
{ inputFile :: Maybe FilePath
|
| 146 |
, outputFile :: Maybe FilePath
|
| 147 |
}
|
| 148 |
|
| 149 |
options :: [Opt.OptDescr (Options -> Options)]
|
| 150 |
options =
|
| 151 |
[ let inFile (Just f) o
|
| 152 |
| f /= "-" = o { inputFile = Just f }
|
| 153 |
inFile _ o = o { inputFile = Nothing }
|
| 154 |
in Opt.Option ['i'] ["input"] (Opt.OptArg inFile "file")
|
| 155 |
"input Electric Boogaloo schema"
|
| 156 |
, let outFile (Just f) o
|
| 157 |
| f /= "-" = o { outputFile = Just f }
|
| 158 |
outFile _ o = o { outputFile = Nothing }
|
| 159 |
in Opt.Option ['o'] ["output"] (Opt.OptArg outFile "file")
|
| 160 |
"output SQLite schema"
|
| 161 |
]
|
| 162 |
|
| 163 |
guard :: Either String a -> IO a
|
| 164 |
guard (Left err) = do
|
| 165 |
Sys.hPutStrLn Sys.stderr err
|
| 166 |
Sys.exitFailure
|
| 167 |
guard (Right x) = return x
|
| 168 |
|
| 169 |
header :: String
|
| 170 |
header = "Electric Boogaloo"
|
| 171 |
|
130 | 172 |
main :: IO ()
|
131 | 173 |
main = do
|
132 | |
cs <- T.getContents
|
133 | |
case parse cs of
|
134 | |
Left err -> putStrLn err
|
135 | |
Right ds -> do
|
136 | |
case check ds of
|
137 | |
Left err -> putStrLn err
|
138 | |
Right () -> mapM_ pprint (rev ds)
|
| 174 |
args <- Sys.getArgs
|
| 175 |
opts <- guard $ case Opt.getOpt Opt.Permute options args of
|
| 176 |
(optsApp, [], []) -> return optsApp
|
| 177 |
_ -> Left (Opt.usageInfo header options)
|
| 178 |
let o = foldl (.) id opts (Options Nothing Nothing)
|
| 179 |
cs <- case inputFile o of
|
| 180 |
Nothing -> T.getContents
|
| 181 |
Just f -> T.readFile f
|
| 182 |
decls <- guard (parse cs)
|
| 183 |
() <- guard (check decls)
|
| 184 |
outH <- case outputFile o of
|
| 185 |
Nothing -> return Sys.stdout
|
| 186 |
Just f -> Sys.openFile f Sys.ReadMode
|
| 187 |
mapM_ (flip pprint outH) (rev decls)
|