@@ -20,12 +20,12 @@ module Language.PureScript.CodeGen.JS (
2020 ModuleType(..),
2121 declToJs,
2222 moduleToJs,
23− isIdent
23+ identNeedsEscaping
2424) where
2525
2626import Data.Maybe (catMaybes, fromJust, fromMaybe)
2727import Data.Function (on)
28−import Data.List (nub, (\\), delete)
28+import Data.List (nub, (\\), delete, sortBy)
2929
3030import Control.Monad (replicateM, forM)
3131import Control.Applicative
@@ -42,7 +42,6 @@ import Language.PureScript.CodeGen.Common
4242import Language.PureScript.Environment
4343import Language.PureScript.Supply
4444import Language.PureScript.Traversals (sndM)
45−
4645import qualified Language.PureScript.Constants as C
4746
4847-- |
@@ -81,14 +80,19 @@ importToJs mt opts mn = JSVariableIntroduction (moduleNameToJs mn) (Just moduleB
8180 Globals -> JSAccessor (moduleNameToJs mn) (JSVar (fromJust (optionsBrowserNamespace opts)))
8281
8382imports :: Declaration -> [ModuleName]
84−imports =
85− let (f, _, _, _, _) = everythingOnValues (++) (const []) collect (const []) (const []) (const [])
86− in f
83+imports (ImportDeclaration mn _ _) = [mn]
84+imports other =
85+ let (f, _, _, _, _) = everythingOnValues (++) (const []) collectV collectB (const []) (const [])
86+ in f other
8787 where
88− collect :: Value -> [ModuleName]
89− collect (Var (Qualified (Just mn) _)) = [mn]
90− collect (Constructor (Qualified (Just mn) _)) = [mn]
91− collect _ = []
88+ collectV :: Value -> [ModuleName]
89+ collectV (Var (Qualified (Just mn) _)) = [mn]
90+ collectV (Constructor (Qualified (Just mn) _)) = [mn]
91+ collectV (TypeClassDictionaryConstructorApp (Qualified (Just mn) _) _) = [mn]
92+ collectV _ = []
93+ collectB :: Binder -> [ModuleName]
94+ collectB (ConstructorBinder (Qualified (Just mn) _) _) = [mn]
95+ collectB _ = []
9296
9397-- |
9498-- Generate code in the simplified Javascript intermediate representation for a declaration
@@ -102,19 +106,48 @@ declToJs opts mp (BindingGroupDeclaration vals) e = do
102106 js <- valueToJs opts mp e val
103107 return $ JSVariableIntroduction (identToJs ident) (Just js)
104108 return $ Just jss
105−declToJs _ mp (DataDeclaration _ _ ctors) _ = do
109+declToJs _ mp (DataDeclaration _ _ ctors) e = do
106110 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) [])
114+ ]
108115 where
109− go :: ProperName -> Integer -> [Type] -> [JS] -> JS
110− go pn _ [] values =
111− JSObjectLiteral [ ("ctor", JSStringLiteral (show (Qualified (Just mp) pn))), ("values", JSArrayLiteral $ reverse values) ]
112− go pn index (_ : tys') values =
116+ makeConstructor :: String -> Int -> JS
117+ makeConstructor ctorName n =
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)
124+ go pn index n values =
113125 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))])
115127declToJs opts mp (DataBindingGroupDeclaration ds) e = do
116128 jss <- mapM (\decl -> declToJs opts mp decl e) ds
117129 return $ Just $ concat $ catMaybes jss
130+declToJs _ _ (TypeClassDeclaration name _ supers members) _ =
131+ return $ Just $ [
132+ JSFunction (Just $ runProperName name) (identToJs `map` args)
133+ (JSBlock $ assn `map` args)]
134+ where
135+ assn :: Ident -> JS
136+ assn arg = JSAssignment (accessor arg (JSVar "this")) (var arg)
137+ args :: [Ident]
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
144+ ]
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"
118151declToJs _ _ (ExternDeclaration _ _ (Just js) _) _ = return $ Just [js]
119152declToJs opts mp (PositionedDeclaration _ d) e = declToJs opts mp d e
120153declToJs _ _ _ _ = return Nothing
@@ -126,6 +159,7 @@ exportToJs :: DeclarationRef -> [(String, JS)]
126159exportToJs (TypeRef _ (Just dctors)) = map ((\n -> (n, var (Ident n))) . runProperName) dctors
127160exportToJs (ValueRef name) = [(runIdent name, var name)]
128161exportToJs (TypeInstanceRef name) = [(runIdent name, var name)]
162+exportToJs (TypeClassRef name) = [(runProperName name, var $ Ident $ runProperName name)]
129163exportToJs _ = []
130164
131165-- |
@@ -145,8 +179,8 @@ accessor (Ident prop) = accessorString prop
145179accessor (Op op) = JSIndexer (JSStringLiteral op)
146180
147181accessorString :: 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
150184
151185-- |
152186-- Generate code in the simplified Javascript intermediate representation for a value or expression.
@@ -157,11 +191,17 @@ valueToJs _ _ _ (StringLiteral s) = return $ JSStringLiteral s
157191valueToJs _ _ _ (BooleanLiteral b) = return $ JSBooleanLiteral b
158192valueToJs opts m e (ArrayLiteral xs) = JSArrayLiteral <$> mapM (valueToJs opts m e) xs
159193valueToJs 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"
160198valueToJs opts m e (ObjectUpdate o ps) = do
161199 obj <- valueToJs opts m e o
162200 sts <- mapM (sndM (valueToJs opts m e)) ps
163201 extendObj obj sts
164−valueToJs _ m _ (Constructor name) = return $ qualifiedToJS m (Ident . runProperName) name
202+valueToJs _ m e (Constructor name) =
203+ let propName = if isNullaryConstructor e name then "value" else "create"
204+ in return $ JSAccessor propName $ qualifiedToJS m (Ident . runProperName) name
165205valueToJs opts m e (Case values binders) = do
166206 vals <- mapM (valueToJs opts m e) values
167207 bindersToJs opts m e binders vals
@@ -297,7 +337,7 @@ binderToJs m e varName done (ConstructorBinder ctor bs) = do
297337 then
298338 return js
299339 else
300− return [JSIfElse (JSBinary EqualTo (JSAccessor "ctor" (JSVar varName)) (JSStringLiteral (show ctor)))
340+ return [JSIfElse (JSInstanceOf (JSVar varName) (qualifiedToJS m (Ident . runProperName) ctor))
301341 (JSBlock js)
302342 Nothing]
303343 where
@@ -307,7 +347,7 @@ binderToJs m e varName done (ConstructorBinder ctor bs) = do
307347 argVar <- freshName
308348 done'' <- go (index + 1) done' bs'
309349 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)
311351binderToJs m e varName done (ObjectBinder bs) = go done bs
312352 where
313353 go :: (Functor m, Applicative m, Monad m) => [JS] -> [(String, Binder)] -> SupplyT m [JS]
@@ -357,3 +397,11 @@ isOnlyConstructor e ctor =
357397 typeConstructor (Qualified (Just moduleName) _, (tyCtor, _)) = (moduleName, tyCtor)
358398 typeConstructor _ = error "Invalid argument to isOnlyConstructor"
359399
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
403+ where
404+ isFunction :: Type -> Bool
405+ isFunction (ForAll _ t _) = isFunction t
406+ isFunction (TypeApp t _) = isFunction t
407+ isFunction t = t == tyFunction