@@ -17,14 +17,16 @@
18module Language.PureScript.CodeGen.JS (
18module Language.PureScript.CodeGen.JS (
19 module AST,
19 module AST,
21 moduleToJs,
22 moduleToJs,
22− wrapExportsContainer,
26import Data.Maybe (fromMaybe, mapMaybe)
26import Data.Maybe (fromMaybe, mapMaybe)
27import Data.Function (on)
27import Data.Function (on)
28+import Data.List (nub, (\\))
29+import Data.Generics (mkQ, everything)
29import Control.Arrow (second)
31import Control.Arrow (second)
30import Control.Monad (replicateM, forM)
32import Control.Monad (replicateM, forM)
@@ -41,26 +43,45 @@ import Language.PureScript.Types
41import Language.PureScript.Optimizer
43import Language.PureScript.Optimizer
42import Language.PureScript.CodeGen.Common
44import Language.PureScript.CodeGen.Common
43import Language.PureScript.Environment
45import Language.PureScript.Environment
44−import qualified Language.PureScript.Constants as C
46+
48+-- Different types of modules which are supported
50+data ModuleType = CommonJS | Globals
47-- Generate code in the simplified Javascript intermediate representation for all declarations in a
53-- Generate code in the simplified Javascript intermediate representation for all declarations in a
50−moduleToJs :: Options -> Module -> Environment -> Maybe JS
56+moduleToJs :: ModuleType -> Options -> Module -> Environment -> [JS]
51−moduleToJs opts (Module name decls (Just exps)) env =
57+moduleToJs mt opts (Module name decls (Just exps)) env = case mt of
52− case jsDecls of
58+ CommonJS -> moduleBody ++ [JSAssignment (JSAccessor "exports" (JSVar "module")) moduleExports]
53− [] -> Nothing
59+ Globals ->
54− _ -> Just $ JSAssignment (JSAccessor (moduleNameToJs name) (JSVar C._ps)) $
60+ [ JSAssignment (JSAccessor (moduleNameToJs name) (JSVar (optionsBrowserNamespace opts))) (
55− JSApp (JSFunction Nothing [] (JSBlock $
61+ JSApp (JSFunction Nothing [] (JSBlock (moduleBody ++ [JSReturn moduleExports]))) []
56− JSVariableIntroduction "module" (Just $ JSObjectLiteral []) :
62+ )
59− [JSReturn $ JSVar "module"])) []
65+ moduleBody = JSStringLiteral "use strict" : jsImports ++ jsDecls
66+ moduleExports = JSObjectLiteral $ concatMap exportToJs exps
61 jsDecls = (concat $ mapMaybe (\decl -> fmap (map $ optimize opts) $ declToJs opts name decl env) decls)
67 jsDecls = (concat $ mapMaybe (\decl -> fmap (map $ optimize opts) $ declToJs opts name decl env) decls)
62− jsExports = concatMap exportToJs exps
68+ jsImports = map (importToJs mt opts) . (\\ [name]) . nub $ concatMap imports decls
63−moduleToJs _ _ _ = error "Exports should have been elaborated in name desugaring"
69+moduleToJs _ _ _ _ = error "Exports should have been elaborated in name desugaring"
71+importToJs :: ModuleType -> Options -> ModuleName -> JS
72+importToJs mt opts mn = JSVariableIntroduction (moduleNameToJs mn) (Just moduleBody)
74+ moduleBody = case mt of
75+ CommonJS -> JSApp (JSVar "require") [JSStringLiteral (runModuleName mn)]
76+ Globals -> JSAccessor (runModuleName mn) (JSVar (optionsBrowserNamespace opts))
78+imports :: Declaration -> [ModuleName]
79+imports = everything (++) (mkQ [] collect)
81+ collect :: Value -> [ModuleName]
82+ collect (Var (Qualified (Just mn) _)) = [mn]
83+ collect (Constructor (Qualified (Just mn) _)) = [mn]
66-- Generate code in the simplified Javascript intermediate representation for a declaration
87-- Generate code in the simplified Javascript intermediate representation for a declaration
@@ -87,22 +108,14 @@ declToJs opts mp (PositionedDeclaration _ d) e = declToJs opts mp d e
87declToJs _ _ _ _ = Nothing
108declToJs _ _ _ _ = Nothing
90−-- Generate code in the simplified Javascript intermediate representation for an export from a
111+-- Generate key//value pairs for an object literal exporting values from a module.
93−exportToJs :: DeclarationRef -> [JS]
113+exportToJs :: DeclarationRef -> [(String, JS)]
94−exportToJs (TypeRef _ (Just dctors)) = flip map dctors (export . Ident . runProperName)
114+exportToJs (TypeRef _ (Just dctors)) = map ((\n -> (n, var (Ident n))) . runProperName) dctors
95−exportToJs (ValueRef name) = [export name]
115+exportToJs (ValueRef name) = [(runIdent name, var name)]
96−exportToJs (TypeInstanceRef name) = [export name]
116+exportToJs (TypeInstanceRef name) = [(runIdent name, var name)]
97exportToJs _ = []
117exportToJs _ = []
100−-- Generate code in the simplified Javascript intermediate representation for assigning an exported
101−-- value to the current module object.
103−export :: Ident -> JS
104−export ident = JSAssignment (accessor ident (JSVar "module")) (var ident)
107-- Generate code in the simplified Javascript intermediate representation for a variable based on a
120-- Generate code in the simplified Javascript intermediate representation for a variable based on a
108-- PureScript identifier.
121-- PureScript identifier.
@@ -225,7 +238,7 @@ varToJs m qual = qualifiedToJS m id qual
225-- variable that may have a qualified name.
238-- variable that may have a qualified name.
227qualifiedToJS :: ModuleName -> (a -> Ident) -> Qualified a -> JS
240qualifiedToJS :: ModuleName -> (a -> Ident) -> Qualified a -> JS
228−qualifiedToJS m f (Qualified (Just m') a) | m /= m' = accessor (f a) (JSAccessor (moduleNameToJs m') $ JSVar C._ps)
241+qualifiedToJS m f (Qualified (Just m') a) | m /= m' = accessor (f a) (JSVar (moduleNameToJs m'))
229qualifiedToJS _ f (Qualified _ a) = JSVar $ identToJs (f a)
242qualifiedToJS _ f (Qualified _ a) = JSVar $ identToJs (f a)
@@ -328,13 +341,3 @@ isOnlyConstructor e ctor =
328 numConstructors ty = length $ filter (((==) `on` typeConstructor) ty) $ M.toList $ dataConstructors e
341 numConstructors ty = length $ filter (((==) `on` typeConstructor) ty) $ M.toList $ dataConstructors e
329 typeConstructor (Qualified (Just moduleName) _, (tyCtor, _)) = (moduleName, tyCtor)
342 typeConstructor (Qualified (Just moduleName) _, (tyCtor, _)) = (moduleName, tyCtor)
330 typeConstructor _ = error "Invalid argument to isOnlyConstructor"
343 typeConstructor _ = error "Invalid argument to isOnlyConstructor"
332−wrapExportsContainer :: Options -> [JS] -> JS
333−wrapExportsContainer opts modules = JSApp (JSFunction Nothing [C._ps] $ JSBlock $ JSStringLiteral "use strict" : modules) [exportSelector]
335− exportSelector = JSConditional (JSBinary And (JSBinary NotEqualTo (JSTypeOf $ JSVar "module") (JSStringLiteral "undefined")) (JSAccessor "exports" (JSVar "module")))
336− (JSAccessor "exports" (JSVar "module"))
337− (JSConditional (JSBinary NotEqualTo (JSTypeOf $ JSVar "window") (JSStringLiteral "undefined"))
338− (JSAssignment (JSAccessor browserNamespace (JSVar "window")) (JSBinary Or (JSAccessor browserNamespace (JSVar "window")) (JSObjectLiteral [])))
339− (JSApp (JSFunction Nothing [] $ JSBlock [JSThrow $ JSStringLiteral "PureScript doesn't know how to export modules in the current environment"]) []))
340− browserNamespace = optionsBrowserNamespace opts