forml-0.1.1: src/hs/Main.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverlappingInstances #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE ViewPatterns #-}
module Main(main) where
import Text.InterpolatedString.Perl6
import Control.Concurrent
import Control.Monad.State hiding (lift)
import System.Directory
import System.Environment
import System.IO
import Data.List as L
import Forml.CLI
import Forml.Closure
import Forml.Doc
import Forml.Javascript
import Forml.Javascript.Backend
import Forml.Javascript.Test
import Forml.Javascript.Utils (prelude)
import qualified Forml.Optimize as O
import Forml.Parser
import Forml.Static
import Forml.TypeCheck hiding (split)
import Data.String.Utils (split)
to_parsed :: Title -> Source -> TypeSystem -> Either [Error] (TypeSystem, Program)
to_parsed name src env = case parseForml name src of
Left x -> Left [show x]
Right x -> case tiProgram x env of
(as, []) -> Right (as, x)
(_, y) -> Left y
parse_forml :: [Filename] -> IO ([Filename], TypeSystem, [(Program, Source)], [Title])
parse_forml filenames =
do sources <- mapM get_source filenames
foldM parse' ("prelude.forml" : filenames, [], [], []) (prelude' : sources)
where parse' :: ([Filename], TypeSystem, [(Program, Source)], [Title]) -> String -> IO ([Filename], TypeSystem, [(Program, Source)], [Title])
parse' (zs, ts, as, titles) src'' =
do let (title, src) = get_title (head . split "." . last . split "/" . head $ zs) src''
let src' = to_literate (head zs) . (++ "\n") $ src
(ts', as') <- monitor [qq|Loading {head zs}|] $ return$ to_parsed (head zs) src' ts
return (tail zs, ts ++ ts', as ++ [(as', src')], titles ++ [title])
get_source filename =
do hFile <- openFile filename ReadMode
hGetContents hFile
gen_js :: [Source] -> [Program] -> (String, [String])
gen_js src p = (g, h)
where g = unserialize $ zipWith (render whole_program) src p
h = map (unserialize . (:[])) $ zipWith (render_spec whole_program) src p
unserialize x = compress $ read' prelude ++ "\n" ++ (unlines $ map read' x)
read' xs @ ('"':_) = read xs
read' x = x
whole_program = Program $ get_program p
get_program (Program ss: ps) = ss ++ get_program ps
get_program [] = []
main :: IO ()
main = do args <- getArgs
main' args
main' :: [String] -> IO ()
main' (parseArgs -> rc') =
if watch rc'
then watch' rc'
else compile rc'
where f (x, y) = show x ++ "\n " ++ concat (L.intersperse "\n " (map show y)) ++ "\n\n "
watch' rc =
do x <- mapM getModificationTime . inputs $ rc
compile rc
putStr "Waiting ..."
hFlush stdout
wait rc x
wait rc x =
do threadDelay 1000
x' <- mapM getModificationTime . inputs $ rc
if x /= x' then do putStr "\r"
watch' rc
else wait rc x
compile rc =
do (_, types, src', titles) <- parse_forml$ inputs rc
let src'' = O.run_optimizer (fmap fst src') types
let (js', tests') = gen_js (fmap snd src') src''
-- writeFile "prelude.types" (B.toString $ S.encode as)
js <- if optimize rc
then monitor [qq|Closure {output rc}.js |]$ closure_local js' "ADVANCED_OPTIMIZATIONS"
else do warn "Closure [libs]" js'
tests <- case rc of
RunConfig { optimize = True, run_tests = Phantom } ->
zipWithM (\title t -> monitor [qq|Closure {title}.spec.js |]$ closure_local t "SIMPLE_OPTIMIZATIONS") titles tests'
_ -> warn "Closure [tests]" tests'
writeFile (output rc ++ ".js") js
zipWithM writeFile (map (++ ".spec.js") titles) tests
if write_docs rc
then let programs = map fst src'
sources = map snd src'
in do docs js tests titles programs sources
else monitor "Docs" $ return $ Right ()
sequence (zipWith (test rc js) titles tests)
if (show_types rc)
then putStrLn ("\nTypes\n\n " ++ concat (map f types))
else return ()