git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Initial CommonJS modules commit
commit51eced9e1c468de92c05832f23801da2a625a301 authorPhil Freeman <paf31@cantab.net> dateFri 11 Apr 2014, 18:19 (13 years ago) parent32532d8
6 files changed+66−89
src/Language/PureScript.hs+7−7 src/Language/PureScript/CodeGen/JS.hs+41−38 src/Language/PureScript/Constants.hs−3 src/Language/PureScript/Names.hs+4 src/Language/PureScript/Optimizer/Inliner.hs+7−20 src/Language/PureScript/Optimizer/MagicDo.hs+7−21
src/Language/PureScript.hs+7−7
@@ -37,7 +37,7 @@ import Data.List (find, sortBy, groupBy, intercalate)
3737import Data.Time.Clock
3838import Data.Function (on)
3939import Data.Generics (mkQ, everything)
40−import Data.Maybe (fromMaybe, mapMaybe)
40+import Data.Maybe (fromMaybe)
4141import Control.Monad.Error
4242import Control.Monad.State.Lazy
4343import Control.Arrow ((&&&))
@@ -78,10 +78,11 @@ compile' env opts ms = do
7878 let elim = if null entryPoints then regrouped else eliminateDeadCode entryPoints regrouped
7979 let codeGenModules = moduleNameFromString `map` optionsCodeGenModules opts
8080 let modulesToCodeGen = if null codeGenModules then elim else filter (\(Module mn _ _) -> mn `elem` codeGenModules) elim
81− let js = mapMaybe (flip (moduleToJs opts) env') modulesToCodeGen
81+ let js = JSVariableIntroduction (optionsBrowserNamespace opts) (Just (JSObjectLiteral []))
82+ : concatMap (\m -> moduleToJs Globals opts m env') modulesToCodeGen
8283 let exts = intercalate "\n" . map (`moduleToPs` env') $ modulesToCodeGen
8384 js' <- generateMain env' opts js
84− return (prettyPrintJS [wrapExportsContainer opts js'], exts, env')
85+ return (prettyPrintJS js', exts, env')
8586 where
8687 mainModuleIdent = moduleNameFromString <$> optionsMain opts
8788
@@ -128,7 +129,7 @@ generateMain env opts js =
128129 Just mmi -> do
129130 when ((mmi, Ident C.main) `M.notMember` names env) $
130131 Left $ show mmi ++ "." ++ C.main ++ " is undefined"
131− return $ js ++ [JSApp (JSAccessor C.main (JSAccessor (moduleNameToJs mmi) (JSVar C._ps))) []]
132+ return $ js ++ [JSApp (JSAccessor C.main (JSVar (moduleNameToJs mmi))) []]
132133 _ -> return js
133134
134135-- |
@@ -206,11 +207,10 @@ make opts ms = do
206207 regrouped <- liftError . stringifyErrorStack True . createBindingGroups moduleName' . collapseBindingGroups $ elaborated
207208
208209 let mod' = Module moduleName' regrouped exps
209− js = moduleToJs opts mod' env'
210+ js = prettyPrintJS $ moduleToJs CommonJS opts mod' env'
210211 exts = moduleToPs mod' env'
211− js' = maybe "" (prettyPrintJS . return . wrapExportsContainer opts . return) js
212212
213− writeTextFile jsFile js'
213+ writeTextFile jsFile js
214214 writeTextFile externsFile exts
215215
216216 go env' ms'
src/Language/PureScript/CodeGen/JS.hs+41−38
@@ -17,14 +17,16 @@
1717
1818module Language.PureScript.CodeGen.JS (
1919 module AST,
20+ ModuleType(..),
2021 declToJs,
2122 moduleToJs,
22− wrapExportsContainer,
2323 isIdent
2424) where
2525
2626import Data.Maybe (fromMaybe, mapMaybe)
2727import Data.Function (on)
28+import Data.List (nub, (\\))
29+import Data.Generics (mkQ, everything)
2830
2931import Control.Arrow (second)
3032import Control.Monad (replicateM, forM)
@@ -41,26 +43,45 @@ import Language.PureScript.Types
4143import Language.PureScript.Optimizer
4244import Language.PureScript.CodeGen.Common
4345import Language.PureScript.Environment
44−import qualified Language.PureScript.Constants as C
46+
47+-- |
48+-- Different types of modules which are supported
49+--
50+data ModuleType = CommonJS | Globals
4551
4652-- |
4753-- Generate code in the simplified Javascript intermediate representation for all declarations in a
4854-- module.
4955--
50−moduleToJs :: Options -> Module -> Environment -> Maybe JS
51−moduleToJs opts (Module name decls (Just exps)) env =
52− case jsDecls of
53− [] -> Nothing
54− _ -> Just $ JSAssignment (JSAccessor (moduleNameToJs name) (JSVar C._ps)) $
55− JSApp (JSFunction Nothing [] (JSBlock $
56− JSVariableIntroduction "module" (Just $ JSObjectLiteral []) :
57− jsDecls ++
58− jsExports ++
59− [JSReturn $ JSVar "module"])) []
56+moduleToJs :: ModuleType -> Options -> Module -> Environment -> [JS]
57+moduleToJs mt opts (Module name decls (Just exps)) env = case mt of
58+ CommonJS -> moduleBody ++ [JSAssignment (JSAccessor "exports" (JSVar "module")) moduleExports]
59+ Globals ->
60+ [ JSAssignment (JSAccessor (moduleNameToJs name) (JSVar (optionsBrowserNamespace opts))) (
61+ JSApp (JSFunction Nothing [] (JSBlock (moduleBody ++ [JSReturn moduleExports]))) []
62+ )
63+ ]
6064 where
65+ moduleBody = JSStringLiteral "use strict" : jsImports ++ jsDecls
66+ moduleExports = JSObjectLiteral $ concatMap exportToJs exps
6167 jsDecls = (concat $ mapMaybe (\decl -> fmap (map $ optimize opts) $ declToJs opts name decl env) decls)
62− jsExports = concatMap exportToJs exps
63−moduleToJs _ _ _ = error "Exports should have been elaborated in name desugaring"
68+ jsImports = map (importToJs mt opts) . (\\ [name]) . nub $ concatMap imports decls
69+moduleToJs _ _ _ _ = error "Exports should have been elaborated in name desugaring"
70+
71+importToJs :: ModuleType -> Options -> ModuleName -> JS
72+importToJs mt opts mn = JSVariableIntroduction (moduleNameToJs mn) (Just moduleBody)
73+ where
74+ moduleBody = case mt of
75+ CommonJS -> JSApp (JSVar "require") [JSStringLiteral (runModuleName mn)]
76+ Globals -> JSAccessor (runModuleName mn) (JSVar (optionsBrowserNamespace opts))
77+
78+imports :: Declaration -> [ModuleName]
79+imports = everything (++) (mkQ [] collect)
80+ where
81+ collect :: Value -> [ModuleName]
82+ collect (Var (Qualified (Just mn) _)) = [mn]
83+ collect (Constructor (Qualified (Just mn) _)) = [mn]
84+ collect _ = []
6485
6586-- |
6687-- 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
87108declToJs _ _ _ _ = Nothing
88109
89110-- |
90−-- Generate code in the simplified Javascript intermediate representation for an export from a
91−-- module.
111+-- Generate key//value pairs for an object literal exporting values from a module.
92112--
93−exportToJs :: DeclarationRef -> [JS]
94−exportToJs (TypeRef _ (Just dctors)) = flip map dctors (export . Ident . runProperName)
95−exportToJs (ValueRef name) = [export name]
96−exportToJs (TypeInstanceRef name) = [export name]
113+exportToJs :: DeclarationRef -> [(String, JS)]
114+exportToJs (TypeRef _ (Just dctors)) = map ((\n -> (n, var (Ident n))) . runProperName) dctors
115+exportToJs (ValueRef name) = [(runIdent name, var name)]
116+exportToJs (TypeInstanceRef name) = [(runIdent name, var name)]
97117exportToJs _ = []
98118
99−-- |
100−-- Generate code in the simplified Javascript intermediate representation for assigning an exported
101−-- value to the current module object.
102−--
103−export :: Ident -> JS
104−export ident = JSAssignment (accessor ident (JSVar "module")) (var ident)
105−
106119-- |
107120-- Generate code in the simplified Javascript intermediate representation for a variable based on a
108121-- PureScript identifier.
@@ -225,7 +238,7 @@ varToJs m qual = qualifiedToJS m id qual
225238-- variable that may have a qualified name.
226239--
227240qualifiedToJS :: 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'))
229242qualifiedToJS _ f (Qualified _ a) = JSVar $ identToJs (f a)
230243
231244-- |
@@ -328,13 +341,3 @@ isOnlyConstructor e ctor =
328341 numConstructors ty = length $ filter (((==) `on` typeConstructor) ty) $ M.toList $ dataConstructors e
329342 typeConstructor (Qualified (Just moduleName) _, (tyCtor, _)) = (moduleName, tyCtor)
330343 typeConstructor _ = error "Invalid argument to isOnlyConstructor"
331−
332−wrapExportsContainer :: Options -> [JS] -> JS
333−wrapExportsContainer opts modules = JSApp (JSFunction Nothing [C._ps] $ JSBlock $ JSStringLiteral "use strict" : modules) [exportSelector]
334− where
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
src/Language/PureScript/Constants.hs−3
@@ -180,9 +180,6 @@ main = "main"
180180
181181-- Code Generation
182182
183−_ps :: String
184−_ps = "_ps"
185−
186183__superclasses :: String
187184__superclasses = "__superclasses"
188185
src/Language/PureScript/Names.hs+4
@@ -33,6 +33,10 @@ data Ident
3333 --
3434 | Op String deriving (Eq, Ord, Data, Typeable)
3535
36+runIdent :: Ident -> String
37+runIdent (Ident i) = i
38+runIdent (Op op) = op
39+
3640instance Show Ident where
3741 show (Ident s) = s
3842 show (Op op) = '(':op ++ ")"
src/Language/PureScript/Optimizer/Inliner.hs+7−20
@@ -81,12 +81,8 @@ inlineOperator (m, op) f = everywhere (mkT convert)
8181 convert :: JS -> JS
8282 convert (JSApp (JSApp op' [x]) [y]) | isOp op' = f x y
8383 convert other = other
84− isOp (JSAccessor longForm (JSAccessor m' (JSVar _ps))) | m == m' &&
85− _ps == C._ps &&
86− longForm == identToJs (Op op) = True
87− isOp (JSIndexer (JSStringLiteral op') (JSAccessor prelude (JSVar _ps))) | prelude == C.prelude &&
88− _ps == C._ps &&
89− op == op' = True
84+ isOp (JSAccessor longForm (JSVar m')) = m == m' && longForm == identToJs (Op op)
85+ isOp (JSIndexer (JSStringLiteral op') (JSVar m')) = m == m' && op == op'
9086 isOp _ = False
9187
9288inlineCommonOperators :: JS -> JS
@@ -131,11 +127,8 @@ inlineCommonOperators = applyAll
131127 convert :: JS -> JS
132128 convert (JSApp (JSApp (JSApp fn [dict]) [x]) [y]) | isOp fn && isOpDict dictName dict = JSBinary op x y
133129 convert other = other
134− isOp (JSAccessor longForm (JSAccessor prelude (JSVar _))) | prelude == C.prelude &&
135− longForm == identToJs (Op opString) = True
136− isOp (JSIndexer (JSStringLiteral op') (JSAccessor prelude (JSVar _ps))) | prelude == C.prelude &&
137− _ps == C._ps &&
138− opString == op' = True
130+ isOp (JSAccessor longForm (JSAccessor prelude (JSVar _))) = prelude == C.prelude && longForm == identToJs (Op opString)
131+ isOp (JSIndexer (JSStringLiteral op') (JSVar prelude)) = prelude == C.prelude && opString == op'
139132 isOp _ = False
140133 binaryFunction :: String -> String -> BinaryOperator -> JS -> JS
141134 binaryFunction dictName fnName op = everywhere (mkT convert)
@@ -143,9 +136,7 @@ inlineCommonOperators = applyAll
143136 convert :: JS -> JS
144137 convert (JSApp (JSApp (JSApp fn [dict]) [x]) [y]) | isOp fn && isOpDict dictName dict = JSBinary op x y
145138 convert other = other
146− isOp (JSAccessor fnName' (JSAccessor prelude (JSVar _ps))) | prelude == C.prelude &&
147− _ps == C._ps &&
148− fnName == fnName' = True
139+ isOp (JSAccessor fnName' (JSVar prelude)) = prelude == C.prelude && fnName == fnName'
149140 isOp _ = False
150141 unary :: String -> String -> UnaryOperator -> JS -> JS
151142 unary dictName fnName op = everywhere (mkT convert)
@@ -153,11 +144,7 @@ inlineCommonOperators = applyAll
153144 convert :: JS -> JS
154145 convert (JSApp (JSApp fn [dict]) [x]) | isOp fn && isOpDict dictName dict = JSUnary op x
155146 convert other = other
156− isOp (JSAccessor fnName' (JSAccessor prelude (JSVar _ps))) | prelude == C.prelude &&
157− _ps == C._ps &&
158− fnName' == fnName = True
147+ isOp (JSAccessor fnName' (JSVar prelude)) = prelude == C.prelude && fnName' == fnName
159148 isOp _ = False
160− isOpDict dictName (JSApp (JSAccessor prop (JSAccessor prelude (JSVar _ps))) [JSObjectLiteral []]) | prelude == C.prelude &&
161− _ps == C._ps &&
162− prop == dictName = True
149+ isOpDict dictName (JSApp (JSAccessor prop (JSVar prelude)) [JSObjectLiteral []]) = prelude == C.prelude && prop == dictName
163150 isOpDict _ _ = False
src/Language/PureScript/Optimizer/MagicDo.hs+7−21
@@ -80,31 +80,19 @@ magicDo' = everywhere (mkT undo) . everywhere' (mkT convert)
8080 isReturn (JSApp retPoly [effDict]) | isRetPoly retPoly && isEffDict C.monadEffDictionary effDict = True
8181 isReturn _ = False
8282 -- Check if an expression represents the polymorphic >>= function
83− isBindPoly (JSAccessor prop (JSAccessor prelude (JSVar _ps))) | prelude == C.prelude &&
84− _ps == C._ps &&
85− prop == identToJs (Op (C.>>=)) = True
86− isBindPoly (JSIndexer (JSStringLiteral bind) (JSAccessor prelude (JSVar _ps))) | prelude == C.prelude &&
87− _ps == C._ps &&
88− bind == (C.>>=) = True
83+ isBindPoly (JSAccessor prop (JSVar prelude)) = prelude == C.prelude && prop == identToJs (Op (C.>>=))
84+ isBindPoly (JSIndexer (JSStringLiteral bind) (JSVar prelude)) = prelude == C.prelude && bind == (C.>>=)
8985 isBindPoly _ = False
9086 -- Check if an expression represents the polymorphic return function
91− isRetPoly (JSAccessor returnEscaped (JSAccessor prelude (JSVar _ps))) | prelude == C.prelude &&
92− _ps == C._ps &&
93− returnEscaped == C.returnEscaped = True
94− isRetPoly (JSIndexer (JSStringLiteral return') (JSAccessor prelude (JSVar _ps))) | prelude == C.prelude &&
95− _ps == C._ps &&
96− return' == C.return = True
87+ isRetPoly (JSAccessor returnEscaped (JSVar prelude)) = prelude == C.prelude && returnEscaped == C.returnEscaped
88+ isRetPoly (JSIndexer (JSStringLiteral return') (JSVar prelude)) = prelude == C.prelude && return' == C.return
9789 isRetPoly _ = False
9890 -- Check if an expression represents a function in the Ef module
99− isEffFunc name (JSAccessor name' (JSAccessor eff (JSVar _ps))) | eff == C.eff &&
100− _ps == C._ps &&
101− name == name' = True
91+ isEffFunc name (JSAccessor name' (JSVar eff)) = eff == C.eff && name == name'
10292 isEffFunc _ _ = False
10393 -- Check if an expression represents the Monad Eff dictionary
10494 isEffDict name (JSApp (JSVar ident) [JSObjectLiteral []]) | ident == name = True
105− isEffDict name (JSApp (JSAccessor prop (JSAccessor eff (JSVar _ps))) [JSObjectLiteral []]) | eff == C.eff &&
106− _ps == C._ps &&
107− prop == name = True
95+ isEffDict name (JSApp (JSAccessor prop (JSVar eff)) [JSObjectLiteral []]) = eff == C.eff && prop == name
10896 isEffDict _ _ = False
10997 -- Remove __do function applications which remain after desugaring
11098 undo :: JS -> JS
@@ -147,9 +135,7 @@ inlineST = everywhere (mkT convertBlock)
147135 JSAssignment (JSIndexer i arr) val
148136 convert _ other = other
149137 -- Check if an expression represents a function in the ST module
150− isSTFunc name (JSAccessor name' (JSAccessor st (JSVar _ps))) | st == C.st &&
151− _ps == C._ps &&
152− name == name' = True
138+ isSTFunc name (JSAccessor name' (JSVar st)) = st == C.st && name == name'
153139 isSTFunc _ _ = False
154140 -- Find all ST Refs initialized in this block
155141 findSTRefsIn = everything (++) (mkQ [] isSTRef)