@@ -13,21 +13,22 @@
14-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
16−{-# LANGUAGE GADTs, ViewPatterns #-}
16+{-# LANGUAGE GADTs, ViewPatterns, FlexibleContexts #-}
18module Language.PureScript.CodeGen.JS (
18module Language.PureScript.CodeGen.JS (
19 module AST,
19 module AST,
20 module Common,
20 module Common,
22 moduleToJs
21 moduleToJs
25import Data.List ((\\), delete)
24import Data.List ((\\), delete)
26import Data.Maybe (mapMaybe)
25import Data.Maybe (mapMaybe)
26+import qualified Data.Traversable as T (traverse)
28import Control.Applicative
28import Control.Applicative
29import Control.Arrow ((&&&))
29import Control.Arrow ((&&&))
30import Control.Monad (foldM, replicateM, forM)
30import Control.Monad (foldM, replicateM, forM)
31+import Control.Monad.Reader (MonadReader, asks, lift)
32import Language.PureScript.CodeGen.JS.AST as AST
33import Language.PureScript.CodeGen.JS.AST as AST
33import Language.PureScript.CodeGen.JS.Common as Common
34import Language.PureScript.CodeGen.JS.Common as Common
@@ -43,16 +44,18 @@ import qualified Language.PureScript.Constants as C
43-- Generate code in the simplified Javascript intermediate representation for all declarations in a
44-- Generate code in the simplified Javascript intermediate representation for all declarations in a
46−moduleToJs :: (Functor m, Applicative m, Monad m) => Options mode -> Module Ann -> SupplyT m [JS]
47+moduleToJs :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
48+ => Module Ann -> SupplyT m [JS]
47−moduleToJs opts (Module name imps exps foreigns decls) = do
49+moduleToJs (Module name imps exps foreigns decls) = do
50+ additional <- lift $ asks optionsAdditional
48− let jsImports = map (importToJs opts) . delete (ModuleName [ProperName C.prim]) . (\\ [name]) $ imps
51+ jsImports <- lift . T.traverse importToJs . delete (ModuleName [ProperName C.prim]) . (\\ [name]) $ imps
49 let foreigns' = mapMaybe (\(_, js, _) -> js) foreigns
52 let foreigns' = mapMaybe (\(_, js, _) -> js) foreigns
50 jsDecls <- mapM (bindToJs name) decls
53 jsDecls <- mapM (bindToJs name) decls
51− let optimized = concatMap (map $ optimize opts) jsDecls
54+ optimized <- lift $ T.traverse (T.traverse optimize) jsDecls
52 let isModuleEmpty = null exps
55 let isModuleEmpty = null exps
53− let moduleBody = JSStringLiteral "use strict" : jsImports ++ foreigns' ++ optimized
56+ let moduleBody = JSStringLiteral "use strict" : jsImports ++ foreigns' ++ concat optimized
54 let exps' = JSObjectLiteral $ map (runIdent &&& JSVar . identToJs) exps
57 let exps' = JSObjectLiteral $ map (runIdent &&& JSVar . identToJs) exps
55− return $ case optionsAdditional opts of
58+ return $ case additional of
56 MakeOptions -> moduleBody ++ [JSAssignment (JSAccessor "exports" (JSVar "module")) exps']
59 MakeOptions -> moduleBody ++ [JSAssignment (JSAccessor "exports" (JSVar "module")) exps']
57 CompileOptions ns _ _ | not isModuleEmpty ->
60 CompileOptions ns _ _ | not isModuleEmpty ->
58 [ JSVariableIntroduction ns
61 [ JSVariableIntroduction ns
@@ -65,18 +68,19 @@ moduleToJs opts (Module name imps exps foreigns decls) = do
66-- Generates Javascript code for a module import.
69-- Generates Javascript code for a module import.
68−importToJs :: Options mode -> ModuleName -> JS
71+importToJs :: (Monad m, MonadReader (Options mode) m) => ModuleName -> m JS
69−importToJs opts mn =
72+importToJs mn = do
70− JSVariableIntroduction (moduleNameToJs mn) (Just moduleBody)
72− moduleBody = case optionsAdditional opts of
73+ additional <- asks optionsAdditional
74+ let moduleBody = case additional of
73− MakeOptions -> JSApp (JSVar "require") [JSStringLiteral (runModuleName mn)]
75+ MakeOptions -> JSApp (JSVar "require") [JSStringLiteral (runModuleName mn)]
74− CompileOptions ns _ _ -> JSAccessor (moduleNameToJs mn) (JSVar ns)
76+ CompileOptions ns _ _ -> JSAccessor (moduleNameToJs mn) (JSVar ns)
77+ return $ JSVariableIntroduction (moduleNameToJs mn) (Just moduleBody)
77-- Generate code in the simplified Javascript intermediate representation for a declaration
80-- Generate code in the simplified Javascript intermediate representation for a declaration
82+bindToJs :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
79−bindToJs :: (Functor m, Applicative m, Monad m) => ModuleName -> Bind Ann -> SupplyT m [JS]
83+ => ModuleName -> Bind Ann -> SupplyT m [JS]
80bindToJs mp (NonRec ident val) = return <$> nonRecToJS mp ident val
84bindToJs mp (NonRec ident val) = return <$> nonRecToJS mp ident val
81bindToJs mp (Rec vals) = forM vals (uncurry (nonRecToJS mp))
85bindToJs mp (Rec vals) = forM vals (uncurry (nonRecToJS mp))
@@ -86,9 +90,13 @@ bindToJs mp (Rec vals) = forM vals (uncurry (nonRecToJS mp))
87-- The main purpose of this function is to handle code generation for comments.
91-- The main purpose of this function is to handle code generation for comments.
93+nonRecToJS :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
89−nonRecToJS :: (Functor m, Applicative m, Monad m) => ModuleName -> Ident -> Expr Ann -> SupplyT m JS
94+ => ModuleName -> Ident -> Expr Ann -> SupplyT m JS
90−nonRecToJS m i e@(extractAnn -> (_, com, _, _)) | not (null com) =
95+nonRecToJS m i e@(extractAnn -> (_, com, _, _)) | not (null com) = do
96+ withoutComment <- lift $ asks optionsNoComments
98+ then nonRecToJS m i (modifyAnn removeComments e)
91− JSComment com <$> nonRecToJS m i (modifyAnn removeComments e)
99+ else JSComment com <$> nonRecToJS m i (modifyAnn removeComments e)
92nonRecToJS mp ident val = do
100nonRecToJS mp ident val = do
93 js <- valueToJs mp val
101 js <- valueToJs mp val
94 return $ JSVariableIntroduction (identToJs ident) (Just js)
102 return $ JSVariableIntroduction (identToJs ident) (Just js)
@@ -117,7 +125,8 @@ accessorString prop | identNeedsEscaping prop = JSIndexer (JSStringLiteral prop)
118-- Generate code in the simplified Javascript intermediate representation for a value or expression.
126-- Generate code in the simplified Javascript intermediate representation for a value or expression.
128+valueToJs :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
120−valueToJs :: (Functor m, Applicative m, Monad m) => ModuleName -> Expr Ann -> SupplyT m JS
129+ => ModuleName -> Expr Ann -> SupplyT m JS
121valueToJs m (Literal _ l) =
130valueToJs m (Literal _ l) =
122 literalToValueJS m l
131 literalToValueJS m l
123valueToJs m (Var (_, _, _, Just (IsConstructor _ 0)) name) =
132valueToJs m (Var (_, _, _, Just (IsConstructor _ 0)) name) =
@@ -128,7 +137,7 @@ valueToJs m (Accessor _ prop val) =
128 accessorString prop <$> valueToJs m val
137 accessorString prop <$> valueToJs m val
129valueToJs m (ObjectUpdate _ o ps) = do
138valueToJs m (ObjectUpdate _ o ps) = do
130 obj <- valueToJs m o
139 obj <- valueToJs m o
131− sts <- mapM (sndM (valueToJs m)) ps
140+ sts <- mapM (sndM $ valueToJs m) ps
132 extendObj obj sts
141 extendObj obj sts
133valueToJs _ e@(Abs (_, _, _, Just IsTypeClassConstructor) _ _) =
142valueToJs _ e@(Abs (_, _, _, Just IsTypeClassConstructor) _ _) =
134 let args = unAbs e
143 let args = unAbs e
@@ -194,7 +203,8 @@ valueToJs _ (Constructor _ _ (ProperName ctor) arity) =
194iife :: String -> [JS] -> JS
203iife :: String -> [JS] -> JS
195iife v exprs = JSApp (JSFunction Nothing [] (JSBlock $ exprs ++ [JSReturn $ JSVar v])) []
204iife v exprs = JSApp (JSFunction Nothing [] (JSBlock $ exprs ++ [JSReturn $ JSVar v])) []
206+literalToValueJS :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
197−literalToValueJS :: (Functor m, Applicative m, Monad m) => ModuleName -> Literal (Expr Ann) -> SupplyT m JS
207+ => ModuleName -> Literal (Expr Ann) -> SupplyT m JS
198literalToValueJS _ (NumericLiteral n) = return $ JSNumericLiteral n
208literalToValueJS _ (NumericLiteral n) = return $ JSNumericLiteral n
199literalToValueJS _ (StringLiteral s) = return $ JSStringLiteral s
209literalToValueJS _ (StringLiteral s) = return $ JSStringLiteral s
200literalToValueJS _ (BooleanLiteral b) = return $ JSBooleanLiteral b
210literalToValueJS _ (BooleanLiteral b) = return $ JSBooleanLiteral b
@@ -241,9 +251,10 @@ qualifiedToJS _ f (Qualified _ a) = JSVar $ identToJs (f a)
241-- Generate code in the simplified Javascript intermediate representation for pattern match binders
251-- Generate code in the simplified Javascript intermediate representation for pattern match binders
242-- and guards.
252-- and guards.
254+bindersToJs :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
244−bindersToJs :: (Functor m, Applicative m, Monad m) => ModuleName -> [CaseAlternative Ann] -> [JS] -> SupplyT m JS
255+ => ModuleName -> [CaseAlternative Ann] -> [JS] -> SupplyT m JS
245bindersToJs m binders vals = do
256bindersToJs m binders vals = do
246− valNames <- replicateM (length vals) freshName
257+ valNames <- replicateM (length vals) $ freshName
247 let assignments = zipWith JSVariableIntroduction valNames (map Just vals)
258 let assignments = zipWith JSVariableIntroduction valNames (map Just vals)
248 jss <- forM binders $ \(CaseAlternative bs result) -> do
259 jss <- forM binders $ \(CaseAlternative bs result) -> do
249 ret <- guardsToJs result
260 ret <- guardsToJs result
@@ -251,14 +262,16 @@ bindersToJs m binders vals = do
251 return $ JSApp (JSFunction Nothing [] (JSBlock (assignments ++ concat jss ++ [JSThrow $ JSUnary JSNew $ JSApp (JSVar "Error") [JSStringLiteral "Failed pattern match"]])))
262 return $ JSApp (JSFunction Nothing [] (JSBlock (assignments ++ concat jss ++ [JSThrow $ JSUnary JSNew $ JSApp (JSVar "Error") [JSStringLiteral "Failed pattern match"]])))
265+ go :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
254− go :: (Functor m, Applicative m, Monad m) => [String] -> [JS] -> [Binder Ann] -> SupplyT m [JS]
266+ => [String] -> [JS] -> [Binder Ann] -> SupplyT m [JS]
255 go _ done [] = return done
267 go _ done [] = return done
256 go (v:vs) done' (b:bs) = do
268 go (v:vs) done' (b:bs) = do
257 done'' <- go vs done' bs
269 done'' <- go vs done' bs
258 binderToJs m v done'' b
270 binderToJs m v done'' b
259 go _ _ _ = error "Invalid arguments to bindersToJs"
271 go _ _ _ = error "Invalid arguments to bindersToJs"
273+ guardsToJs :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
261− guardsToJs :: (Functor m, Applicative m, Monad m) => Either [(Guard Ann, Expr Ann)] (Expr Ann) -> SupplyT m [JS]
274+ => Either [(Guard Ann, Expr Ann)] (Expr Ann) -> SupplyT m [JS]
262 guardsToJs (Left gs) = forM gs $ \(cond, val) -> do
275 guardsToJs (Left gs) = forM gs $ \(cond, val) -> do
263 cond' <- valueToJs m cond
276 cond' <- valueToJs m cond
264 done <- valueToJs m val
277 done <- valueToJs m val
@@ -269,7 +282,8 @@ bindersToJs m binders vals = do
269-- Generate code in the simplified Javascript intermediate representation for a pattern match
282-- Generate code in the simplified Javascript intermediate representation for a pattern match
270-- binder.
283-- binder.
285+binderToJs :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
272−binderToJs :: (Functor m, Applicative m, Monad m) => ModuleName -> String -> [JS] -> Binder Ann -> SupplyT m [JS]
286+ => ModuleName -> String -> [JS] -> Binder Ann -> SupplyT m [JS]
273binderToJs _ _ done (NullBinder{}) = return done
287binderToJs _ _ done (NullBinder{}) = return done
274binderToJs m varName done (LiteralBinder _ l) =
288binderToJs m varName done (LiteralBinder _ l) =
275 literalToBinderJS m varName done l
289 literalToBinderJS m varName done l
@@ -286,7 +300,8 @@ binderToJs m varName done (ConstructorBinder (_, _, _, Just (IsConstructor ctorT
286 (JSBlock js)
300 (JSBlock js)
303+ go :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
289− go :: (Functor m, Applicative m, Monad m) => Integer -> [JS] -> [Binder Ann] -> SupplyT m [JS]
304+ => Integer -> [JS] -> [Binder Ann] -> SupplyT m [JS]
290 go _ done' [] = return done'
305 go _ done' [] = return done'
291 go index done' (binder:bs') = do
306 go index done' (binder:bs') = do
292 argVar <- freshName
307 argVar <- freshName
@@ -316,7 +331,8 @@ binderToJs m varName done (NamedBinder _ ident binder) = do
316 js <- binderToJs m varName done binder
331 js <- binderToJs m varName done binder
317 return (JSVariableIntroduction (identToJs ident) (Just (JSVar varName)) : js)
332 return (JSVariableIntroduction (identToJs ident) (Just (JSVar varName)) : js)
334+literalToBinderJS :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
319−literalToBinderJS :: (Functor m, Applicative m, Monad m) => ModuleName -> String -> [JS] -> Literal (Binder Ann) -> SupplyT m [JS]
335+ => ModuleName -> String -> [JS] -> Literal (Binder Ann) -> SupplyT m [JS]
320literalToBinderJS _ varName done (NumericLiteral num) =
336literalToBinderJS _ varName done (NumericLiteral num) =
321 return [JSIfElse (JSBinary EqualTo (JSVar varName) (JSNumericLiteral num)) (JSBlock done) Nothing]
337 return [JSIfElse (JSBinary EqualTo (JSVar varName) (JSNumericLiteral num)) (JSBlock done) Nothing]
322literalToBinderJS _ varName done (StringLiteral str) =
338literalToBinderJS _ varName done (StringLiteral str) =
@@ -327,7 +343,8 @@ literalToBinderJS _ varName done (BooleanLiteral False) =
327 return [JSIfElse (JSUnary Not (JSVar varName)) (JSBlock done) Nothing]
343 return [JSIfElse (JSUnary Not (JSVar varName)) (JSBlock done) Nothing]
328literalToBinderJS m varName done (ObjectLiteral bs) = go done bs
344literalToBinderJS m varName done (ObjectLiteral bs) = go done bs
346+ go :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
330− go :: (Functor m, Applicative m, Monad m) => [JS] -> [(String, Binder Ann)] -> SupplyT m [JS]
347+ => [JS] -> [(String, Binder Ann)] -> SupplyT m [JS]
331 go done' [] = return done'
348 go done' [] = return done'
332 go done' ((prop, binder):bs') = do
349 go done' ((prop, binder):bs') = do
333 propVar <- freshName
350 propVar <- freshName
@@ -338,7 +355,8 @@ literalToBinderJS m varName done (ArrayLiteral bs) = do
338 js <- go done 0 bs
355 js <- go done 0 bs
339 return [JSIfElse (JSBinary EqualTo (JSAccessor "length" (JSVar varName)) (JSNumericLiteral (Left (fromIntegral $ length bs)))) (JSBlock js) Nothing]
356 return [JSIfElse (JSBinary EqualTo (JSAccessor "length" (JSVar varName)) (JSNumericLiteral (Left (fromIntegral $ length bs)))) (JSBlock js) Nothing]
358+ go :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
341− go :: (Functor m, Applicative m, Monad m) => [JS] -> Integer -> [Binder Ann] -> SupplyT m [JS]
359+ => [JS] -> Integer -> [Binder Ann] -> SupplyT m [JS]
342 go done' _ [] = return done'
360 go done' _ [] = return done'
343 go done' index (binder:bs') = do
361 go done' index (binder:bs') = do
344 elVar <- freshName
362 elVar <- freshName