@@ -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 _ [])) name) =
132valueToJs m (Var (_, _, _, Just (IsConstructor _ [])) 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
@@ -191,7 +200,8 @@ valueToJs _ (Constructor _ _ (ProperName ctor) fields) =
191iife :: String -> [JS] -> JS
200iife :: String -> [JS] -> JS
192iife v exprs = JSApp (JSFunction Nothing [] (JSBlock $ exprs ++ [JSReturn $ JSVar v])) []
201iife v exprs = JSApp (JSFunction Nothing [] (JSBlock $ exprs ++ [JSReturn $ JSVar v])) []
203+literalToValueJS :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
194−literalToValueJS :: (Functor m, Applicative m, Monad m) => ModuleName -> Literal (Expr Ann) -> SupplyT m JS
204+ => ModuleName -> Literal (Expr Ann) -> SupplyT m JS
195literalToValueJS _ (NumericLiteral n) = return $ JSNumericLiteral n
205literalToValueJS _ (NumericLiteral n) = return $ JSNumericLiteral n
196literalToValueJS _ (StringLiteral s) = return $ JSStringLiteral s
206literalToValueJS _ (StringLiteral s) = return $ JSStringLiteral s
197literalToValueJS _ (BooleanLiteral b) = return $ JSBooleanLiteral b
207literalToValueJS _ (BooleanLiteral b) = return $ JSBooleanLiteral b
@@ -238,7 +248,8 @@ qualifiedToJS _ f (Qualified _ a) = JSVar $ identToJs (f a)
238-- Generate code in the simplified Javascript intermediate representation for pattern match binders
248-- Generate code in the simplified Javascript intermediate representation for pattern match binders
239-- and guards.
249-- and guards.
251+bindersToJs :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
241−bindersToJs :: (Functor m, Applicative m, Monad m) => ModuleName -> [CaseAlternative Ann] -> [JS] -> SupplyT m JS
252+ => ModuleName -> [CaseAlternative Ann] -> [JS] -> SupplyT m JS
242bindersToJs m binders vals = do
253bindersToJs m binders vals = do
243 valNames <- replicateM (length vals) freshName
254 valNames <- replicateM (length vals) freshName
244 let assignments = zipWith JSVariableIntroduction valNames (map Just vals)
255 let assignments = zipWith JSVariableIntroduction valNames (map Just vals)
@@ -248,14 +259,16 @@ bindersToJs m binders vals = do
248 return $ JSApp (JSFunction Nothing [] (JSBlock (assignments ++ concat jss ++ [JSThrow $ JSUnary JSNew $ JSApp (JSVar "Error") [JSStringLiteral "Failed pattern match"]])))
259 return $ JSApp (JSFunction Nothing [] (JSBlock (assignments ++ concat jss ++ [JSThrow $ JSUnary JSNew $ JSApp (JSVar "Error") [JSStringLiteral "Failed pattern match"]])))
262+ go :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
251− go :: (Functor m, Applicative m, Monad m) => [String] -> [JS] -> [Binder Ann] -> SupplyT m [JS]
263+ => [String] -> [JS] -> [Binder Ann] -> SupplyT m [JS]
252 go _ done [] = return done
264 go _ done [] = return done
253 go (v:vs) done' (b:bs) = do
265 go (v:vs) done' (b:bs) = do
254 done'' <- go vs done' bs
266 done'' <- go vs done' bs
255 binderToJs m v done'' b
267 binderToJs m v done'' b
256 go _ _ _ = error "Invalid arguments to bindersToJs"
268 go _ _ _ = error "Invalid arguments to bindersToJs"
270+ guardsToJs :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
258− guardsToJs :: (Functor m, Applicative m, Monad m) => Either [(Guard Ann, Expr Ann)] (Expr Ann) -> SupplyT m [JS]
271+ => Either [(Guard Ann, Expr Ann)] (Expr Ann) -> SupplyT m [JS]
259 guardsToJs (Left gs) = forM gs $ \(cond, val) -> do
272 guardsToJs (Left gs) = forM gs $ \(cond, val) -> do
260 cond' <- valueToJs m cond
273 cond' <- valueToJs m cond
261 done <- valueToJs m val
274 done <- valueToJs m val
@@ -266,7 +279,8 @@ bindersToJs m binders vals = do
266-- Generate code in the simplified Javascript intermediate representation for a pattern match
279-- Generate code in the simplified Javascript intermediate representation for a pattern match
267-- binder.
280-- binder.
282+binderToJs :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
269−binderToJs :: (Functor m, Applicative m, Monad m) => ModuleName -> String -> [JS] -> Binder Ann -> SupplyT m [JS]
283+ => ModuleName -> String -> [JS] -> Binder Ann -> SupplyT m [JS]
270binderToJs _ _ done (NullBinder{}) = return done
284binderToJs _ _ done (NullBinder{}) = return done
271binderToJs m varName done (LiteralBinder _ l) =
285binderToJs m varName done (LiteralBinder _ l) =
272 literalToBinderJS m varName done l
286 literalToBinderJS m varName done l
@@ -283,7 +297,8 @@ binderToJs m varName done (ConstructorBinder (_, _, _, Just (IsConstructor ctorT
283 (JSBlock js)
297 (JSBlock js)
300+ go :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
286− go :: (Functor m, Applicative m, Monad m) => [(Ident, Binder Ann)] -> [JS] -> SupplyT m [JS]
301+ => [(Ident, Binder Ann)] -> [JS] -> SupplyT m [JS]
287 go [] done' = return done'
302 go [] done' = return done'
288 go ((field, binder) : remain) done' = do
303 go ((field, binder) : remain) done' = do
289 argVar <- freshName
304 argVar <- freshName
@@ -313,7 +328,8 @@ binderToJs m varName done (NamedBinder _ ident binder) = do
313 js <- binderToJs m varName done binder
328 js <- binderToJs m varName done binder
314 return (JSVariableIntroduction (identToJs ident) (Just (JSVar varName)) : js)
329 return (JSVariableIntroduction (identToJs ident) (Just (JSVar varName)) : js)
331+literalToBinderJS :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
316−literalToBinderJS :: (Functor m, Applicative m, Monad m) => ModuleName -> String -> [JS] -> Literal (Binder Ann) -> SupplyT m [JS]
332+ => ModuleName -> String -> [JS] -> Literal (Binder Ann) -> SupplyT m [JS]
317literalToBinderJS _ varName done (NumericLiteral num) =
333literalToBinderJS _ varName done (NumericLiteral num) =
318 return [JSIfElse (JSBinary EqualTo (JSVar varName) (JSNumericLiteral num)) (JSBlock done) Nothing]
334 return [JSIfElse (JSBinary EqualTo (JSVar varName) (JSNumericLiteral num)) (JSBlock done) Nothing]
319literalToBinderJS _ varName done (StringLiteral str) =
335literalToBinderJS _ varName done (StringLiteral str) =
@@ -324,7 +340,8 @@ literalToBinderJS _ varName done (BooleanLiteral False) =
324 return [JSIfElse (JSUnary Not (JSVar varName)) (JSBlock done) Nothing]
340 return [JSIfElse (JSUnary Not (JSVar varName)) (JSBlock done) Nothing]
325literalToBinderJS m varName done (ObjectLiteral bs) = go done bs
341literalToBinderJS m varName done (ObjectLiteral bs) = go done bs
343+ go :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
327− go :: (Functor m, Applicative m, Monad m) => [JS] -> [(String, Binder Ann)] -> SupplyT m [JS]
344+ => [JS] -> [(String, Binder Ann)] -> SupplyT m [JS]
328 go done' [] = return done'
345 go done' [] = return done'
329 go done' ((prop, binder):bs') = do
346 go done' ((prop, binder):bs') = do
330 propVar <- freshName
347 propVar <- freshName
@@ -335,7 +352,8 @@ literalToBinderJS m varName done (ArrayLiteral bs) = do
335 js <- go done 0 bs
352 js <- go done 0 bs
336 return [JSIfElse (JSBinary EqualTo (JSAccessor "length" (JSVar varName)) (JSNumericLiteral (Left (fromIntegral $ length bs)))) (JSBlock js) Nothing]
353 return [JSIfElse (JSBinary EqualTo (JSAccessor "length" (JSVar varName)) (JSNumericLiteral (Left (fromIntegral $ length bs)))) (JSBlock js) Nothing]
355+ go :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)
338− go :: (Functor m, Applicative m, Monad m) => [JS] -> Integer -> [Binder Ann] -> SupplyT m [JS]
356+ => [JS] -> Integer -> [Binder Ann] -> SupplyT m [JS]
339 go done' _ [] = return done'
357 go done' _ [] = return done'
340 go done' index (binder:bs') = do
358 go done' index (binder:bs') = do
341 elVar <- freshName
359 elVar <- freshName