/src/HOE.hs

https://github.com/Phlogistique/hoe · Haskell · 134 lines · 117 code · 16 blank · 1 comment · 7 complexity · 5e313fe2928d32cf808f525e7d51652f MD5 · raw file

  1. {-# Language DeriveDataTypeable #-}
  2. module Main (main) where
  3. import Control.Monad hiding (join)
  4. import Control.Monad.Error.Class
  5. import System.Console.CmdArgs as CA
  6. import System.IO
  7. import Language.Haskell.Interpreter as HInt hiding (name)
  8. data Option
  9. = Option
  10. { join :: Bool
  11. , inplace :: Maybe String
  12. , script :: String
  13. , inputFiles :: [String]
  14. , modules :: [String]
  15. }
  16. deriving (Show, Data, Typeable)
  17. option =
  18. Option {
  19. join = def &= help "Join a type of script",
  20. inplace = def &= help "Edit files in place (make bkup if EXT supplied)" &= opt "" &= typ "EXT",
  21. script = def &= argPos 0 &= typ "SCRIPT",
  22. inputFiles = def &= args &= typ "FILES",
  23. modules = def &= help "Import a module before running the script"
  24. &= opt ""
  25. &= explicit
  26. &= name "mod"
  27. &= name "m" }
  28. &= program "hoe"
  29. &= summary "Haskell One-liner Evaluator, (c) Hideyuki Tanaka 2010"
  30. main :: IO ()
  31. main = do
  32. opts <- cmdArgs option
  33. r <- evalOneLiner opts
  34. case r of
  35. Left err ->
  36. case err of
  37. WontCompile errs ->
  38. hPutStrLn stderr $ "compile error: " ++ unlines (map errMsg errs)
  39. UnknownError msg ->
  40. hPutStrLn stderr $ msg
  41. _ ->
  42. hPutStrLn stderr $ show err
  43. Right _ ->
  44. return ()
  45. evalOneLiner opts = runInterpreter $ do
  46. reset
  47. setImportsQ $
  48. [ ("Prelude", Nothing)
  49. , ("Control.Applicative", Nothing)
  50. , ("Control.Monad", Nothing)
  51. , ("Data.Char", Nothing)
  52. , ("Data.List", Nothing)
  53. , ("Data.Ord", Nothing)
  54. , ("System.IO", Nothing)
  55. , ("System.IO.Unsafe", Nothing)
  56. , ("Text.Printf", Nothing)
  57. ] ++ [ (m, Nothing) | m <- modules opts ]
  58. set [ installedModulesInScope HInt.:= True ]
  59. let evals
  60. = [ evalShow
  61. , evalIO
  62. , evalIOShow
  63. , evalStrListToStrList
  64. , evalStrListToStr
  65. , evalStrToStrList
  66. , evalStrLineToStrLine
  67. , evalStrLineToStr
  68. , evalStrToStr
  69. , evalCharToChar
  70. , evalErr
  71. ]
  72. let intr = genInteract opts
  73. choice (if join opts then reverse evals else evals) (script opts) intr
  74. genInteract :: Main.Option -> (String -> String) -> IO ()
  75. genInteract opts =
  76. case (inputFiles opts, inplace opts) of
  77. ([], _) -> interact
  78. (files, Nothing) -> \f -> do
  79. forM_ files $ \file -> do
  80. s <- readFile file
  81. putStr $ f s
  82. (files, Just ext) -> \f -> do
  83. forM_ files $ \file -> do
  84. s <- readFile file
  85. when (ext /= "") $ do
  86. writeFile (file ++ ext) s
  87. length s `seq` writeFile file (f s)
  88. choice fs s intr = foldl1 (<|>) (map (\f -> f s intr) fs)
  89. f <|> g = catchError f (\e -> g)
  90. evalStr s _ = do
  91. r <- interpret s (as :: IO String)
  92. liftIO $ putStrLn =<< r
  93. evalStrI s intr = do
  94. r <- interpret s (as :: String -> String)
  95. liftIO $ intr r
  96. evalShow s =
  97. evalStr $ "return $ show (" ++ s ++ ")"
  98. evalIO s =
  99. evalStr $ "((" ++ s ++ ") >>= \\() -> return \"\")"
  100. evalIOShow s =
  101. evalStr $ "return . show =<< (" ++ s ++ ")"
  102. evalStrListToStrList s =
  103. evalStrI $ "unlines . (" ++ s ++ ") . lines"
  104. evalStrListToStr s = do
  105. evalStrI $ "(++\"\\n\") . (" ++ s ++ ") . lines"
  106. evalStrToStrList s =
  107. evalStrI $ "unlines . (" ++ s ++ ")"
  108. evalStrLineToStrLine s = do
  109. evalStrI $ "unlines . map snd . sort . zipWith (" ++ s ++ ") [1..] . lines"
  110. evalStrLineToStr s = do
  111. evalStrI $ "unlines . zipWith (" ++ s ++ ") [1..] . lines"
  112. evalStrToStr s = do
  113. evalStrI $ "unlines . map (" ++ s ++ ") . lines"
  114. evalCharToChar s = do
  115. evalStrI $ "map (" ++ s ++ ")"
  116. evalErr s _ = do
  117. t <- typeOf s
  118. fail $ "cannot evaluate: " ++ t