@@ -20,12 +20,12 @@ module Language.PureScript.CodeGen.JS (
20 ModuleType(..),
20 ModuleType(..),
22 moduleToJs,
22 moduleToJs,
23− isIdent
23+ identNeedsEscaping
26import Data.Maybe (catMaybes, fromJust, fromMaybe)
26import Data.Maybe (catMaybes, fromJust, fromMaybe)
27import Data.Function (on)
27import Data.Function (on)
28−import Data.List (nub, (\\), delete)
28+import Data.List (nub, (\\), delete, sortBy)
30import Control.Monad (replicateM, forM)
30import Control.Monad (replicateM, forM)
31import Control.Applicative
31import Control.Applicative
@@ -42,7 +42,6 @@ import Language.PureScript.CodeGen.Common
42import Language.PureScript.Environment
42import Language.PureScript.Environment
43import Language.PureScript.Supply
43import Language.PureScript.Supply
44import Language.PureScript.Traversals (sndM)
44import Language.PureScript.Traversals (sndM)
46import qualified Language.PureScript.Constants as C
45import qualified Language.PureScript.Constants as C
@@ -81,14 +80,19 @@ importToJs mt opts mn = JSVariableIntroduction (moduleNameToJs mn) (Just moduleB
81 Globals -> JSAccessor (moduleNameToJs mn) (JSVar (fromJust (optionsBrowserNamespace opts)))
80 Globals -> JSAccessor (moduleNameToJs mn) (JSVar (fromJust (optionsBrowserNamespace opts)))
83imports :: Declaration -> [ModuleName]
82imports :: Declaration -> [ModuleName]
84−imports =
83+imports (ImportDeclaration mn _ _) = [mn]
85− let (f, _, _, _, _) = everythingOnValues (++) (const []) collect (const []) (const []) (const [])
85+ let (f, _, _, _, _) = everythingOnValues (++) (const []) collectV collectB (const []) (const [])
88− collect :: Value -> [ModuleName]
88+ collectV :: Value -> [ModuleName]
89− collect (Var (Qualified (Just mn) _)) = [mn]
89+ collectV (Var (Qualified (Just mn) _)) = [mn]
90− collect (Constructor (Qualified (Just mn) _)) = [mn]
90+ collectV (Constructor (Qualified (Just mn) _)) = [mn]
91− collect _ = []
91+ collectV (TypeClassDictionaryConstructorApp (Qualified (Just mn) _) _) = [mn]
93+ collectB :: Binder -> [ModuleName]
94+ collectB (ConstructorBinder (Qualified (Just mn) _) _) = [mn]
94-- Generate code in the simplified Javascript intermediate representation for a declaration
98-- Generate code in the simplified Javascript intermediate representation for a declaration
@@ -102,19 +106,48 @@ declToJs opts mp (BindingGroupDeclaration vals) e = do
102 js <- valueToJs opts mp e val
106 js <- valueToJs opts mp e val
103 return $ JSVariableIntroduction (identToJs ident) (Just js)
107 return $ JSVariableIntroduction (identToJs ident) (Just js)
104 return $ Just jss
108 return $ Just jss
105−declToJs _ mp (DataDeclaration _ _ ctors) _ = do
109+declToJs _ mp (DataDeclaration _ _ ctors) e = do
106 return $ Just $ flip concatMap ctors $ \(pn@(ProperName ctor), tys) ->
110 return $ Just $ flip concatMap ctors $ \(pn@(ProperName ctor), tys) ->
107− [JSVariableIntroduction ctor (Just (go pn 0 tys []))]
111+ let propName = if isNullaryConstructor e (Qualified (Just mp) pn) then "value" else "create"
112+ in [ makeConstructor ctor (length tys)
113+ , JSAssignment (JSAccessor propName (JSVar ctor)) (go pn 0 (length tys) [])
109− go :: ProperName -> Integer -> [Type] -> [JS] -> JS
116+ makeConstructor :: String -> Int -> JS
110− go pn _ [] values =
117+ makeConstructor ctorName n =
111− JSObjectLiteral [ ("ctor", JSStringLiteral (show (Qualified (Just mp) pn))), ("values", JSArrayLiteral $ reverse values) ]
118+ let
119+ args = [ "value" ++ show index | index <- [0..n-1] ]
120+ body = [ JSAssignment (JSAccessor arg (JSVar "this")) (JSVar arg) | arg <- args ]
121+ in JSFunction (Just ctorName) args (JSBlock body)
122+ go :: ProperName -> Int -> Int -> [JS] -> JS
123+ go pn _ 0 values = JSApp (JSNew (JSVar (runProperName pn))) (reverse values)
112− go pn index (_ : tys') values =
124+ go pn index n values =
113 JSFunction Nothing ["value" ++ show index]
125 JSFunction Nothing ["value" ++ show index]
114− (JSBlock [JSReturn (go pn (index + 1) tys' (JSVar ("value" ++ show index) : values))])
126+ (JSBlock [JSReturn (go pn (index + 1) (n - 1) (JSVar ("value" ++ show index) : values))])
115declToJs opts mp (DataBindingGroupDeclaration ds) e = do
127declToJs opts mp (DataBindingGroupDeclaration ds) e = do
116 jss <- mapM (\decl -> declToJs opts mp decl e) ds
128 jss <- mapM (\decl -> declToJs opts mp decl e) ds
117 return $ Just $ concat $ catMaybes jss
129 return $ Just $ concat $ catMaybes jss
130+declToJs _ _ (TypeClassDeclaration name _ supers members) _ =
132+ JSFunction (Just $ runProperName name) (identToJs `map` args)
133+ (JSBlock $ assn `map` args)]
136+ assn arg = JSAssignment (accessor arg (JSVar "this")) (var arg)
138+ args = sortBy (compare `on` runIdent) $ memberNames ++ superNames
139+ memberNames :: [Ident]
140+ memberNames = memberToName `map` members
141+ superNames :: [Ident]
142+ superNames = [ toSuperName superclass index
143+ | (index, (superclass, _)) <- zip [0..] supers
145+ toSuperName :: Qualified ProperName -> Integer -> Ident
146+ toSuperName pn index = Ident $ C.__superclass_ ++ show pn ++ "_" ++ show index
147+ memberToName :: Declaration -> Ident
148+ memberToName (TypeDeclaration ident _) = ident
149+ memberToName (PositionedDeclaration _ d) = memberToName d
150+ memberToName _ = error "Invalid declaration in type class definition"
118declToJs _ _ (ExternDeclaration _ _ (Just js) _) _ = return $ Just [js]
151declToJs _ _ (ExternDeclaration _ _ (Just js) _) _ = return $ Just [js]
119declToJs opts mp (PositionedDeclaration _ d) e = declToJs opts mp d e
152declToJs opts mp (PositionedDeclaration _ d) e = declToJs opts mp d e
120declToJs _ _ _ _ = return Nothing
153declToJs _ _ _ _ = return Nothing
@@ -126,6 +159,7 @@ exportToJs :: DeclarationRef -> [(String, JS)]
126exportToJs (TypeRef _ (Just dctors)) = map ((\n -> (n, var (Ident n))) . runProperName) dctors
159exportToJs (TypeRef _ (Just dctors)) = map ((\n -> (n, var (Ident n))) . runProperName) dctors
127exportToJs (ValueRef name) = [(runIdent name, var name)]
160exportToJs (ValueRef name) = [(runIdent name, var name)]
128exportToJs (TypeInstanceRef name) = [(runIdent name, var name)]
161exportToJs (TypeInstanceRef name) = [(runIdent name, var name)]
162+exportToJs (TypeClassRef name) = [(runProperName name, var $ Ident $ runProperName name)]
129exportToJs _ = []
163exportToJs _ = []
@@ -145,8 +179,8 @@ accessor (Ident prop) = accessorString prop
145accessor (Op op) = JSIndexer (JSStringLiteral op)
179accessor (Op op) = JSIndexer (JSStringLiteral op)
147accessorString :: String -> JS -> JS
181accessorString :: String -> JS -> JS
148−accessorString prop | isIdent prop = JSAccessor prop
149− | otherwise = JSIndexer (JSStringLiteral prop)
182+accessorString prop | identNeedsEscaping prop = JSIndexer (JSStringLiteral prop)
183+ | otherwise = JSAccessor prop
152-- Generate code in the simplified Javascript intermediate representation for a value or expression.
186-- Generate code in the simplified Javascript intermediate representation for a value or expression.
@@ -157,11 +191,17 @@ valueToJs _ _ _ (StringLiteral s) = return $ JSStringLiteral s
157valueToJs _ _ _ (BooleanLiteral b) = return $ JSBooleanLiteral b
191valueToJs _ _ _ (BooleanLiteral b) = return $ JSBooleanLiteral b
158valueToJs opts m e (ArrayLiteral xs) = JSArrayLiteral <$> mapM (valueToJs opts m e) xs
192valueToJs opts m e (ArrayLiteral xs) = JSArrayLiteral <$> mapM (valueToJs opts m e) xs
159valueToJs opts m e (ObjectLiteral ps) = JSObjectLiteral <$> mapM (sndM (valueToJs opts m e)) ps
193valueToJs opts m e (ObjectLiteral ps) = JSObjectLiteral <$> mapM (sndM (valueToJs opts m e)) ps
194+valueToJs opts m e (TypeClassDictionaryConstructorApp name (TypedValue _ (ObjectLiteral ps) _)) =
195+ JSApp (JSNew (qualifiedToJS m (Ident . runProperName) name)) <$> mapM (valueToJs opts m e . snd) (sortBy (compare `on` fst) ps)
196+valueToJs _ _ _ TypeClassDictionaryConstructorApp{} =
197+ error "TypeClassDictionaryConstructorApp did not contain object literal"
160valueToJs opts m e (ObjectUpdate o ps) = do
198valueToJs opts m e (ObjectUpdate o ps) = do
161 obj <- valueToJs opts m e o
199 obj <- valueToJs opts m e o
162 sts <- mapM (sndM (valueToJs opts m e)) ps
200 sts <- mapM (sndM (valueToJs opts m e)) ps
163 extendObj obj sts
201 extendObj obj sts
202+valueToJs _ m e (Constructor name) =
203+ let propName = if isNullaryConstructor e name then "value" else "create"
164−valueToJs _ m _ (Constructor name) = return $ qualifiedToJS m (Ident . runProperName) name
204+ in return $ JSAccessor propName $ qualifiedToJS m (Ident . runProperName) name
165valueToJs opts m e (Case values binders) = do
205valueToJs opts m e (Case values binders) = do
166 vals <- mapM (valueToJs opts m e) values
206 vals <- mapM (valueToJs opts m e) values
167 bindersToJs opts m e binders vals
207 bindersToJs opts m e binders vals
@@ -297,7 +337,7 @@ binderToJs m e varName done (ConstructorBinder ctor bs) = do
298 return js
338 return js
300− return [JSIfElse (JSBinary EqualTo (JSAccessor "ctor" (JSVar varName)) (JSStringLiteral (show ctor)))
340+ return [JSIfElse (JSInstanceOf (JSVar varName) (qualifiedToJS m (Ident . runProperName) ctor))
301 (JSBlock js)
341 (JSBlock js)
@@ -307,7 +347,7 @@ binderToJs m e varName done (ConstructorBinder ctor bs) = do
307 argVar <- freshName
347 argVar <- freshName
308 done'' <- go (index + 1) done' bs'
348 done'' <- go (index + 1) done' bs'
309 js <- binderToJs m e argVar done'' binder
349 js <- binderToJs m e argVar done'' binder
310− return (JSVariableIntroduction argVar (Just (JSIndexer (JSNumericLiteral (Left index)) (JSAccessor "values" (JSVar varName)))) : js)
350+ return (JSVariableIntroduction argVar (Just (JSAccessor ("value" ++ show index) (JSVar varName))) : js)
311binderToJs m e varName done (ObjectBinder bs) = go done bs
351binderToJs m e varName done (ObjectBinder bs) = go done bs
313 go :: (Functor m, Applicative m, Monad m) => [JS] -> [(String, Binder)] -> SupplyT m [JS]
353 go :: (Functor m, Applicative m, Monad m) => [JS] -> [(String, Binder)] -> SupplyT m [JS]
@@ -357,3 +397,11 @@ isOnlyConstructor e ctor =
357 typeConstructor (Qualified (Just moduleName) _, (tyCtor, _)) = (moduleName, tyCtor)
397 typeConstructor (Qualified (Just moduleName) _, (tyCtor, _)) = (moduleName, tyCtor)
358 typeConstructor _ = error "Invalid argument to isOnlyConstructor"
398 typeConstructor _ = error "Invalid argument to isOnlyConstructor"
400+isNullaryConstructor :: Environment -> Qualified ProperName -> Bool
401+isNullaryConstructor e ctor =
402+ not . isFunction . snd . fromMaybe (error "Data constructor not found") $ ctor `M.lookup` dataConstructors e
404+ isFunction :: Type -> Bool
405+ isFunction (ForAll _ t _) = isFunction t
406+ isFunction (TypeApp t _) = isFunction t
407+ isFunction t = t == tyFunction