@@ -13,21 +13,22 @@
1313--
1414-----------------------------------------------------------------------------
1515
16−{-# LANGUAGE GADTs, ViewPatterns #-}
16+{-# LANGUAGE GADTs, ViewPatterns, FlexibleContexts #-}
1717
1818module Language.PureScript.CodeGen.JS (
1919 module AST,
2020 module Common,
21− bindToJs,
2221 moduleToJs
2322) where
2423
2524import Data.List ((\\), delete)
2625import Data.Maybe (mapMaybe)
26+import qualified Data.Traversable as T (traverse)
2727
2828import Control.Applicative
2929import Control.Arrow ((&&&))
3030import Control.Monad (foldM, replicateM, forM)
31+import Control.Monad.Reader (MonadReader, asks, lift)
3132
3233import Language.PureScript.CodeGen.JS.AST as AST
3334import Language.PureScript.CodeGen.JS.Common as Common
@@ -43,16 +44,18 @@ import qualified Language.PureScript.Constants as C
4344-- Generate code in the simplified Javascript intermediate representation for all declarations in a
4445-- module.
4546--
46−moduleToJs :: (Functor m, Applicative m, Monad m) => Options mode -> Module Ann -> SupplyT m [JS]
47−moduleToJs opts (Module name imps exps foreigns decls) = do
48− let jsImports = map (importToJs opts) . delete (ModuleName [ProperName C.prim]) . (\\ [name]) $ imps
47+moduleToJs :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
48+ => Module Ann -> SupplyT m [JS]
49+moduleToJs (Module name imps exps foreigns decls) = do
50+ additional <- lift $ asks optionsAdditional
51+ jsImports <- lift . T.traverse importToJs . delete (ModuleName [ProperName C.prim]) . (\\ [name]) $ imps
4952 let foreigns' = mapMaybe (\(_, js, _) -> js) foreigns
5053 jsDecls <- mapM (bindToJs name) decls
51− let optimized = concatMap (map $ optimize opts) jsDecls
54+ optimized <- lift $ T.traverse (T.traverse optimize) jsDecls
5255 let isModuleEmpty = null exps
53− let moduleBody = JSStringLiteral "use strict" : jsImports ++ foreigns' ++ optimized
56+ let moduleBody = JSStringLiteral "use strict" : jsImports ++ foreigns' ++ concat optimized
5457 let exps' = JSObjectLiteral $ map (runIdent &&& JSVar . identToJs) exps
55− return $ case optionsAdditional opts of
58+ return $ case additional of
5659 MakeOptions -> moduleBody ++ [JSAssignment (JSAccessor "exports" (JSVar "module")) exps']
5760 CompileOptions ns _ _ | not isModuleEmpty ->
5861 [ JSVariableIntroduction ns
@@ -65,18 +68,19 @@ moduleToJs opts (Module name imps exps foreigns decls) = do
6568-- |
6669-- Generates Javascript code for a module import.
6770--
68−importToJs :: Options mode -> ModuleName -> JS
69−importToJs opts mn =
70− JSVariableIntroduction (moduleNameToJs mn) (Just moduleBody)
71− where
72− moduleBody = case optionsAdditional opts of
73− MakeOptions -> JSApp (JSVar "require") [JSStringLiteral (runModuleName mn)]
74− CompileOptions ns _ _ -> JSAccessor (moduleNameToJs mn) (JSVar ns)
71+importToJs :: (Monad m, MonadReader (Options mode) m) => ModuleName -> m JS
72+importToJs mn = do
73+ additional <- asks optionsAdditional
74+ let moduleBody = case additional of
75+ MakeOptions -> JSApp (JSVar "require") [JSStringLiteral (runModuleName mn)]
76+ CompileOptions ns _ _ -> JSAccessor (moduleNameToJs mn) (JSVar ns)
77+ return $ JSVariableIntroduction (moduleNameToJs mn) (Just moduleBody)
7578
7679-- |
7780-- Generate code in the simplified Javascript intermediate representation for a declaration
7881--
79−bindToJs :: (Functor m, Applicative m, Monad m) => ModuleName -> Bind Ann -> SupplyT m [JS]
82+bindToJs :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
83+ => ModuleName -> Bind Ann -> SupplyT m [JS]
8084bindToJs mp (NonRec ident val) = return <$> nonRecToJS mp ident val
8185bindToJs mp (Rec vals) = forM vals (uncurry (nonRecToJS mp))
8286
@@ -86,9 +90,13 @@ bindToJs mp (Rec vals) = forM vals (uncurry (nonRecToJS mp))
8690--
8791-- The main purpose of this function is to handle code generation for comments.
8892--
89−nonRecToJS :: (Functor m, Applicative m, Monad m) => ModuleName -> Ident -> Expr Ann -> SupplyT m JS
90−nonRecToJS m i e@(extractAnn -> (_, com, _, _)) | not (null com) =
91− JSComment com <$> nonRecToJS m i (modifyAnn removeComments e)
93+nonRecToJS :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
94+ => ModuleName -> Ident -> Expr Ann -> SupplyT m JS
95+nonRecToJS m i e@(extractAnn -> (_, com, _, _)) | not (null com) = do
96+ withoutComment <- lift $ asks optionsNoComments
97+ if withoutComment
98+ then nonRecToJS m i (modifyAnn removeComments e)
99+ else JSComment com <$> nonRecToJS m i (modifyAnn removeComments e)
92100nonRecToJS mp ident val = do
93101 js <- valueToJs mp val
94102 return $ JSVariableIntroduction (identToJs ident) (Just js)
@@ -117,7 +125,8 @@ accessorString prop | identNeedsEscaping prop = JSIndexer (JSStringLiteral prop)
117125-- |
118126-- Generate code in the simplified Javascript intermediate representation for a value or expression.
119127--
120−valueToJs :: (Functor m, Applicative m, Monad m) => ModuleName -> Expr Ann -> SupplyT m JS
128+valueToJs :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
129+ => ModuleName -> Expr Ann -> SupplyT m JS
121130valueToJs m (Literal _ l) =
122131 literalToValueJS m l
123132valueToJs m (Var (_, _, _, Just (IsConstructor _ 0)) name) =
@@ -128,7 +137,7 @@ valueToJs m (Accessor _ prop val) =
128137 accessorString prop <$> valueToJs m val
129138valueToJs m (ObjectUpdate _ o ps) = do
130139 obj <- valueToJs m o
131− sts <- mapM (sndM (valueToJs m)) ps
140+ sts <- mapM (sndM $ valueToJs m) ps
132141 extendObj obj sts
133142valueToJs _ e@(Abs (_, _, _, Just IsTypeClassConstructor) _ _) =
134143 let args = unAbs e
@@ -194,7 +203,8 @@ valueToJs _ (Constructor _ _ (ProperName ctor) arity) =
194203iife :: String -> [JS] -> JS
195204iife v exprs = JSApp (JSFunction Nothing [] (JSBlock $ exprs ++ [JSReturn $ JSVar v])) []
196205
197−literalToValueJS :: (Functor m, Applicative m, Monad m) => ModuleName -> Literal (Expr Ann) -> SupplyT m JS
206+literalToValueJS :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
207+ => ModuleName -> Literal (Expr Ann) -> SupplyT m JS
198208literalToValueJS _ (NumericLiteral n) = return $ JSNumericLiteral n
199209literalToValueJS _ (StringLiteral s) = return $ JSStringLiteral s
200210literalToValueJS _ (BooleanLiteral b) = return $ JSBooleanLiteral b
@@ -241,9 +251,10 @@ qualifiedToJS _ f (Qualified _ a) = JSVar $ identToJs (f a)
241251-- Generate code in the simplified Javascript intermediate representation for pattern match binders
242252-- and guards.
243253--
244−bindersToJs :: (Functor m, Applicative m, Monad m) => ModuleName -> [CaseAlternative Ann] -> [JS] -> SupplyT m JS
254+bindersToJs :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
255+ => ModuleName -> [CaseAlternative Ann] -> [JS] -> SupplyT m JS
245256bindersToJs m binders vals = do
246− valNames <- replicateM (length vals) freshName
257+ valNames <- replicateM (length vals) $ freshName
247258 let assignments = zipWith JSVariableIntroduction valNames (map Just vals)
248259 jss <- forM binders $ \(CaseAlternative bs result) -> do
249260 ret <- guardsToJs result
@@ -251,14 +262,16 @@ bindersToJs m binders vals = do
251262 return $ JSApp (JSFunction Nothing [] (JSBlock (assignments ++ concat jss ++ [JSThrow $ JSUnary JSNew $ JSApp (JSVar "Error") [JSStringLiteral "Failed pattern match"]])))
252263 []
253264 where
254− go :: (Functor m, Applicative m, Monad m) => [String] -> [JS] -> [Binder Ann] -> SupplyT m [JS]
265+ go :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
266+ => [String] -> [JS] -> [Binder Ann] -> SupplyT m [JS]
255267 go _ done [] = return done
256268 go (v:vs) done' (b:bs) = do
257269 done'' <- go vs done' bs
258270 binderToJs m v done'' b
259271 go _ _ _ = error "Invalid arguments to bindersToJs"
260272
261− guardsToJs :: (Functor m, Applicative m, Monad m) => Either [(Guard Ann, Expr Ann)] (Expr Ann) -> SupplyT m [JS]
273+ guardsToJs :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
274+ => Either [(Guard Ann, Expr Ann)] (Expr Ann) -> SupplyT m [JS]
262275 guardsToJs (Left gs) = forM gs $ \(cond, val) -> do
263276 cond' <- valueToJs m cond
264277 done <- valueToJs m val
@@ -269,7 +282,8 @@ bindersToJs m binders vals = do
269282-- Generate code in the simplified Javascript intermediate representation for a pattern match
270283-- binder.
271284--
272−binderToJs :: (Functor m, Applicative m, Monad m) => ModuleName -> String -> [JS] -> Binder Ann -> SupplyT m [JS]
285+binderToJs :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
286+ => ModuleName -> String -> [JS] -> Binder Ann -> SupplyT m [JS]
273287binderToJs _ _ done (NullBinder{}) = return done
274288binderToJs m varName done (LiteralBinder _ l) =
275289 literalToBinderJS m varName done l
@@ -286,7 +300,8 @@ binderToJs m varName done (ConstructorBinder (_, _, _, Just (IsConstructor ctorT
286300 (JSBlock js)
287301 Nothing]
288302 where
289− go :: (Functor m, Applicative m, Monad m) => Integer -> [JS] -> [Binder Ann] -> SupplyT m [JS]
303+ go :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
304+ => Integer -> [JS] -> [Binder Ann] -> SupplyT m [JS]
290305 go _ done' [] = return done'
291306 go index done' (binder:bs') = do
292307 argVar <- freshName
@@ -316,7 +331,8 @@ binderToJs m varName done (NamedBinder _ ident binder) = do
316331 js <- binderToJs m varName done binder
317332 return (JSVariableIntroduction (identToJs ident) (Just (JSVar varName)) : js)
318333
319−literalToBinderJS :: (Functor m, Applicative m, Monad m) => ModuleName -> String -> [JS] -> Literal (Binder Ann) -> SupplyT m [JS]
334+literalToBinderJS :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
335+ => ModuleName -> String -> [JS] -> Literal (Binder Ann) -> SupplyT m [JS]
320336literalToBinderJS _ varName done (NumericLiteral num) =
321337 return [JSIfElse (JSBinary EqualTo (JSVar varName) (JSNumericLiteral num)) (JSBlock done) Nothing]
322338literalToBinderJS _ varName done (StringLiteral str) =
@@ -327,7 +343,8 @@ literalToBinderJS _ varName done (BooleanLiteral False) =
327343 return [JSIfElse (JSUnary Not (JSVar varName)) (JSBlock done) Nothing]
328344literalToBinderJS m varName done (ObjectLiteral bs) = go done bs
329345 where
330− go :: (Functor m, Applicative m, Monad m) => [JS] -> [(String, Binder Ann)] -> SupplyT m [JS]
346+ go :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
347+ => [JS] -> [(String, Binder Ann)] -> SupplyT m [JS]
331348 go done' [] = return done'
332349 go done' ((prop, binder):bs') = do
333350 propVar <- freshName
@@ -338,7 +355,8 @@ literalToBinderJS m varName done (ArrayLiteral bs) = do
338355 js <- go done 0 bs
339356 return [JSIfElse (JSBinary EqualTo (JSAccessor "length" (JSVar varName)) (JSNumericLiteral (Left (fromIntegral $ length bs)))) (JSBlock js) Nothing]
340357 where
341− go :: (Functor m, Applicative m, Monad m) => [JS] -> Integer -> [Binder Ann] -> SupplyT m [JS]
358+ go :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
359+ => [JS] -> Integer -> [Binder Ann] -> SupplyT m [JS]
342360 go done' _ [] = return done'
343361 go done' index (binder:bs') = do
344362 elVar <- freshName