json-autotype-0.2.1.0: GenerateJSONParser.hs
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables, OverloadedStrings #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Main where
import System.IO (withFile, stdin, stderr, stdout, IOMode(..), Handle)
import System.FilePath (FilePath, splitExtension)
import System.Environment (getArgs)
import Control.Arrow ((&&&))
import Control.Lens.TH
import Control.Lens
import Control.Monad (forM, forM_, when)
import Control.Exception(assert)
import qualified Data.ByteString.Lazy.Char8 as BSL
import qualified Data.HashMap.Strict as Map
import qualified Data.Set as Set
import qualified Data.Vector as V
import Data.Aeson
import Data.Aeson.Types
import qualified Data.Text as Text
import qualified Data.Text.IO as Text
import Data.Text (Text)
import Data.Set (Set )
import Data.List (sort, foldl1')
import Data.Ord (Ord(..), comparing)
import Data.Char (isAlpha)
import Control.Monad.State.Class
import Control.Monad.State.Strict(State, runState)
import Data.Hashable (Hashable(..))
import qualified Data.Graph as Graph
import Data.Aeson.AutoType.Type
import Data.Aeson.AutoType.Extract
import Data.Aeson.AutoType.Util
import Data.Aeson.AutoType.Format
import CLI
import HFlags
--import Data.Tuple.Utils (fst3)
fst3 (a, _, _) = a
assertM v = assert v $ return ()
capitalize :: Text -> Text
capitalize input = Text.toUpper (Text.take 1 input)
`Text.append` Text.drop 1 input
header moduleName = Text.unlines ["{-# LANGUAGE TemplateHaskell #-}"
,Text.concat ["module ", capitalize moduleName, " where"]
,""
,"import Data.Text (Text)"
,"import Data.Aeson(decode, Value(..), FromJSON(..),"
," (.:), (.:?), (.!=))"
,"import Data.Aeson.TH"
,""]
-- * Command line flags
defineFlag "filename" (defaultOutputFilename :: FilePath) "Write output to the given file"
defineFlag "suggest" True "Suggest candidates for unification"
defineFlag "autounify" True "Automatically unify suggested candidates"
defineFlag "fakeFlag" True "Ignore this flag - it doesn't exist!!!"
-- Tracing is switched off:
myTrace :: String -> IO ()
myTrace _msg = return ()
--myTrace = putStrLn
main = do filenames <- $initHFlags "json-autotype -- automatic type and parser generation from JSON"
let (moduleName, extension) = splitExtension $
if flags_filename == "-"
then defaultOutputFilename
else flags_filename
assertM (extension == ".hs")
-- TODO: should integrate all inputs into single type set!!!
withFileOrHandle flags_filename WriteMode stdout $ \hOut ->
forM filenames $ \filename ->
withFileOrHandle filename ReadMode stdin $ \hIn ->
do bs <- BSL.hGetContents hIn
Text.hPutStrLn stderr $ "Processing " `Text.append` Text.pack (show moduleName)
myTrace ("Decoded JSON: " ++ show (decode bs :: Maybe Value))
let Just v = decode bs
let t = extractType v
myTrace $ "type: " ++ show t
let splitted = splitTypeByLabel "TopLevel" t
myTrace $ "splitted: " ++ show splitted
Text.hPutStrLn hOut $ header $ Text.pack moduleName
assertM $ not $ any hasNonTopTObj $ Map.elems splitted
let uCands = unificationCandidates splitted
myTrace $ "candidates: " ++ show uCands
when flags_suggest $ forM_ uCands $ \cs -> do
putStr "-- "
Text.putStrLn $ "=" `Text.intercalate` cs
let unified = if flags_autounify
then unifyCandidates uCands splitted
else splitted
myTrace $ "unified: " ++ show unified
Text.hPutStrLn hOut $ displaySplitTypes unified