@@ -18,7 +18,7 @@ module Language.PureScript.CodeGen.JS (
20import Data.Char
20import Data.Char
21−import Data.Maybe (fromMaybe)
21+import Data.Maybe (fromMaybe, mapMaybe)
22import Data.List (intercalate)
22import Data.List (intercalate)
23import qualified Control.Arrow as A
23import qualified Control.Arrow as A
24import Control.Arrow ((<+>), second)
24import Control.Arrow ((<+>), second)
@@ -33,76 +33,100 @@ import Language.PureScript.Pretty.Common
33import Language.PureScript.CodeGen.Monad
33import Language.PureScript.CodeGen.Monad
34import Language.PureScript.CodeGen.JS.AST as AST
34import Language.PureScript.CodeGen.JS.AST as AST
36−declToJs :: Declaration -> Maybe [JS]
36+declToJs :: Maybe Ident -> ModulePath -> Declaration -> Maybe [JS]
37+declToJs mod mp (ValueDeclaration ident (Abs args ret)) =
37−declToJs (ValueDeclaration ident (Abs args ret)) = Just [JSFunction (Just ident) args (JSBlock [JSReturn (valueToJs ret)])]
38+ Just $ JSFunction (Just ident) args (JSBlock [JSReturn (valueToJs mp ret)]) :
39+ maybe [] (return . setProperty (show ident) (JSVar ident)) mod
40+declToJs mod mp (ValueDeclaration ident val) =
38−declToJs (ValueDeclaration ident val) = Just [JSVariableIntroduction ident (valueToJs val)]
41+ Just $ JSVariableIntroduction ident (Just (valueToJs mp val)) :
42+ maybe [] (return . setProperty (show ident) (JSVar ident)) mod
39−declToJs (ExternMemberDeclaration member ident _) =
43+declToJs mod _ (ExternMemberDeclaration member ident _) =
40− Just [JSFunction (Just ident) [Ident "value"] (JSBlock [JSReturn (JSAccessor member (JSVar (Ident "value")))])]
44+ Just $ JSFunction (Just ident) [Ident "value"] (JSBlock [JSReturn (JSAccessor member (JSVar (Ident "value")))]) :
45+ maybe [] (return . setProperty (show ident) (JSVar ident)) mod
41−declToJs (DataDeclaration _ _ ctors) =
46+declToJs mod mp (DataDeclaration _ _ ctors) =
42− Just $ flip map ctors $ \(ctor, maybeTy) ->
47+ Just $ flip concatMap ctors $ \(pn@(ProperName ctor), maybeTy) ->
43− case maybeTy of
50+ case maybeTy of
44− Nothing -> JSVariableIntroduction (Ident ctor) (JSObjectLiteral [ ("ctor", JSStringLiteral ctor) ])
51+ Nothing -> JSVariableIntroduction (Ident ctor) (Just (JSObjectLiteral [ ("ctor", JSStringLiteral (show (Qualified mp pn))) ]))
45− Just _ -> JSFunction (Just (Ident ctor)) [Ident "value"]
52+ Just _ -> JSFunction (Just (Ident ctor)) [Ident "value"]
46− (JSBlock [JSReturn
53+ (JSBlock [JSReturn
47− (JSObjectLiteral [ ("ctor", JSStringLiteral ctor)
54+ (JSObjectLiteral [ ("ctor", JSStringLiteral (show (Qualified mp pn)))
48− , ("value", JSVar (Ident "value")) ])])
55+ , ("value", JSVar (Ident "value")) ])])
56+ in ctorJs : maybe [] (return . setProperty ctor (JSVar (Ident ctor))) mod
57+declToJs mod mp (ModuleDeclaration pn@(ProperName name) decls) =
58+ Just $ [ JSVariableIntroduction (Ident name) Nothing
59+ , JSApp (JSFunction Nothing [Ident name]
60+ (JSBlock (concat $ mapMaybe (declToJs (Just (Ident name)) (subModule mp pn)) decls)))
61+ [JSAssignment (JSAssignVariable (Ident name) )
62+ (JSBinary Or (JSVar (Ident name)) (JSObjectLiteral []))]] ++
63+ maybe [] (return . setProperty name (JSVar (Ident name))) mod
49−declToJs _ = Nothing
64+declToJs _ _ _ = Nothing
51−valueToJs :: Value -> JS
66+setProperty :: String -> JS -> Ident -> JS
52−valueToJs (NumericLiteral n) = JSNumericLiteral n
67+setProperty prop val mod = JSAssignment (JSAssignProperty prop (JSAssignVariable mod)) val
53−valueToJs (StringLiteral s) = JSStringLiteral s
54−valueToJs (BooleanLiteral b) = JSBooleanLiteral b
55−valueToJs (ArrayLiteral xs) = JSArrayLiteral (map valueToJs xs)
56−valueToJs (ObjectLiteral ps) = JSObjectLiteral (map (second valueToJs) ps)
57−valueToJs (ObjectUpdate o ps) = JSApp (JSAccessor "extend" (JSVar (Ident "Object"))) [ valueToJs o, JSObjectLiteral (map (second valueToJs) ps)]
58−valueToJs (Constructor name) = JSVar (Ident name)
59−valueToJs (Block sts) = JSApp (JSFunction Nothing [] (JSBlock (map statementToJs sts))) []
60−valueToJs (Case value binders) = runGen (bindersToJs binders (valueToJs value))
61−valueToJs (IfThenElse cond th el) = JSConditional (valueToJs cond) (valueToJs th) (valueToJs el)
62−valueToJs (Accessor prop val) = JSAccessor prop (valueToJs val)
63−valueToJs (Indexer index val) = JSIndexer (valueToJs index) (valueToJs val)
64−valueToJs (App val args) = JSApp (valueToJs val) (map valueToJs args)
65−valueToJs (Abs args val) = JSFunction Nothing args (JSBlock [JSReturn (valueToJs val)])
66−valueToJs (Unary op val) = JSUnary op (valueToJs val)
67−valueToJs (Binary op v1 v2) = JSBinary op (valueToJs v1) (valueToJs v2)
68−valueToJs (Var ident) = JSVar ident
69−valueToJs (TypedValue val _) = valueToJs val
69+valueToJs :: ModulePath -> Value -> JS
70+valueToJs _ (NumericLiteral n) = JSNumericLiteral n
71+valueToJs _ (StringLiteral s) = JSStringLiteral s
72+valueToJs _ (BooleanLiteral b) = JSBooleanLiteral b
73+valueToJs m (ArrayLiteral xs) = JSArrayLiteral (map (valueToJs m) xs)
74+valueToJs m (ObjectLiteral ps) = JSObjectLiteral (map (second (valueToJs m)) ps)
75+valueToJs m (ObjectUpdate o ps) = JSApp (JSAccessor "extend" (JSVar (Ident "Object"))) [ valueToJs m o, JSObjectLiteral (map (second (valueToJs m)) ps)]
76+valueToJs m (Constructor name) = qualifiedToJS runProperName name
77+valueToJs m (Block sts) = JSApp (JSFunction Nothing [] (JSBlock (map (statementToJs m) sts))) []
78+valueToJs m (Case value binders) = runGen (bindersToJs m binders (valueToJs m value))
79+valueToJs m (IfThenElse cond th el) = JSConditional (valueToJs m cond) (valueToJs m th) (valueToJs m el)
80+valueToJs m (Accessor prop val) = JSAccessor prop (valueToJs m val)
81+valueToJs m (Indexer index val) = JSIndexer (valueToJs m index) (valueToJs m val)
82+valueToJs m (App val args) = JSApp (valueToJs m val) (map (valueToJs m) args)
83+valueToJs m (Abs args val) = JSFunction Nothing args (JSBlock [JSReturn (valueToJs m val)])
84+valueToJs m (Unary op val) = JSUnary op (valueToJs m val)
85+valueToJs m (Binary op v1 v2) = JSBinary op (valueToJs m v1) (valueToJs m v2)
86+valueToJs m (Var ident) = qualifiedToJS identToJs ident
87+valueToJs m (TypedValue val _) = valueToJs m val
89+qualifiedToJS :: (a -> String) -> Qualified a -> JS
90+qualifiedToJS f (Qualified (ModulePath parts) a) = delimited (f a : reverse (map show parts))
92+ delimited [part] = JSVar (Ident (part))
93+ delimited (part:parts) = JSAccessor part (delimited parts)
71−bindersToJs :: [(Binder, Value)] -> JS -> Gen JS
95+bindersToJs :: ModulePath -> [(Binder, Value)] -> JS -> Gen JS
72−bindersToJs binders val = do
96+bindersToJs m binders val = do
73 valName <- fresh
97 valName <- fresh
74− jss <- forM binders $ \(binder, result) -> binderToJs valName [JSReturn (valueToJs result)] binder
98+ jss <- forM binders $ \(binder, result) -> binderToJs m valName [JSReturn (valueToJs m result)] binder
75 return $ JSApp (JSFunction Nothing [Ident valName] (JSBlock (concat jss ++ [JSThrow (JSStringLiteral "Failed pattern match")])))
99 return $ JSApp (JSFunction Nothing [Ident valName] (JSBlock (concat jss ++ [JSThrow (JSStringLiteral "Failed pattern match")])))
78−binderToJs :: String -> [JS] -> Binder -> Gen [JS]
102+binderToJs :: ModulePath -> String -> [JS] -> Binder -> Gen [JS]
79−binderToJs varName done NullBinder = return done
103+binderToJs _ varName done NullBinder = return done
80−binderToJs varName done (StringBinder str) =
104+binderToJs _ varName done (StringBinder str) =
81 return [JSIfElse (JSBinary EqualTo (JSVar (Ident varName)) (JSStringLiteral str)) (JSBlock done) Nothing]
105 return [JSIfElse (JSBinary EqualTo (JSVar (Ident varName)) (JSStringLiteral str)) (JSBlock done) Nothing]
82−binderToJs varName done (NumberBinder num) =
106+binderToJs _ varName done (NumberBinder num) =
83 return [JSIfElse (JSBinary EqualTo (JSVar (Ident varName)) (JSNumericLiteral num)) (JSBlock done) Nothing]
107 return [JSIfElse (JSBinary EqualTo (JSVar (Ident varName)) (JSNumericLiteral num)) (JSBlock done) Nothing]
84−binderToJs varName done (BooleanBinder True) =
108+binderToJs _ varName done (BooleanBinder True) =
85 return [JSIfElse (JSVar (Ident varName)) (JSBlock done) Nothing]
109 return [JSIfElse (JSVar (Ident varName)) (JSBlock done) Nothing]
86−binderToJs varName done (BooleanBinder False) =
110+binderToJs _ varName done (BooleanBinder False) =
87 return [JSIfElse (JSUnary Not (JSVar (Ident varName))) (JSBlock done) Nothing]
111 return [JSIfElse (JSUnary Not (JSVar (Ident varName))) (JSBlock done) Nothing]
88−binderToJs varName done (VarBinder ident) =
112+binderToJs _ varName done (VarBinder ident) =
89− return (JSVariableIntroduction ident (JSVar (Ident varName)) : done)
113+ return (JSVariableIntroduction ident (Just (JSVar (Ident varName))) : done)
90−binderToJs varName done (NullaryBinder ctor) =
114+binderToJs m varName done (NullaryBinder ctor) =
91− return [JSIfElse (JSBinary EqualTo (JSAccessor "ctor" (JSVar (Ident varName))) (JSStringLiteral ctor)) (JSBlock done) Nothing]
115+ return [JSIfElse (JSBinary EqualTo (JSAccessor "ctor" (JSVar (Ident varName))) (JSStringLiteral (show (uncurry Qualified $ qualify m ctor)))) (JSBlock done) Nothing]
92−binderToJs varName done (UnaryBinder ctor b) = do
116+binderToJs m varName done (UnaryBinder ctor b) = do
93 value <- fresh
117 value <- fresh
94− js <- binderToJs value done b
118+ js <- binderToJs m value done b
95− return [JSIfElse (JSBinary EqualTo (JSAccessor "ctor" (JSVar (Ident varName))) (JSStringLiteral ctor)) (JSBlock (JSVariableIntroduction (Ident value) (JSAccessor "value" (JSVar (Ident varName))) : js)) Nothing]
119+ return [JSIfElse (JSBinary EqualTo (JSAccessor "ctor" (JSVar (Ident varName))) (JSStringLiteral (show (uncurry Qualified $ qualify m ctor)))) (JSBlock (JSVariableIntroduction (Ident value) (Just (JSAccessor "value" (JSVar (Ident varName)))) : js)) Nothing]
96−binderToJs varName done (ObjectBinder bs) = go done bs
120+binderToJs m varName done (ObjectBinder bs) = go done bs
98 go :: [JS] -> [(String, Binder)] -> Gen [JS]
122 go :: [JS] -> [(String, Binder)] -> Gen [JS]
99 go done [] = return done
123 go done [] = return done
100 go done ((prop, binder):bs) = do
124 go done ((prop, binder):bs) = do
101 propVar <- fresh
125 propVar <- fresh
102 done' <- go done bs
126 done' <- go done bs
103− js <- binderToJs propVar done' binder
127+ js <- binderToJs m propVar done' binder
104− return (JSVariableIntroduction (Ident propVar) (JSAccessor prop (JSVar (Ident varName))) : js)
128+ return (JSVariableIntroduction (Ident propVar) (Just (JSAccessor prop (JSVar (Ident varName)))) : js)
105−binderToJs varName done (ArrayBinder bs rest) = do
129+binderToJs m varName done (ArrayBinder bs rest) = do
106 js <- go done rest 0 bs
130 js <- go done rest 0 bs
107 return [JSIfElse (JSBinary cmp (JSAccessor "length" (JSVar (Ident varName))) (JSNumericLiteral (Left (fromIntegral $ length bs)))) (JSBlock js) Nothing]
131 return [JSIfElse (JSBinary cmp (JSAccessor "length" (JSVar (Ident varName))) (JSNumericLiteral (Left (fromIntegral $ length bs)))) (JSBlock js) Nothing]
@@ -112,31 +136,31 @@ binderToJs varName done (ArrayBinder bs rest) = do
112 go done Nothing _ [] = return done
136 go done Nothing _ [] = return done
113 go done (Just binder) index [] = do
137 go done (Just binder) index [] = do
114 restVar <- fresh
138 restVar <- fresh
115− js <- binderToJs restVar done binder
139+ js <- binderToJs m restVar done binder
116− return (JSVariableIntroduction (Ident restVar) (JSApp (JSAccessor "slice" (JSVar (Ident varName))) [JSNumericLiteral (Left index)]) : js)
140+ return (JSVariableIntroduction (Ident restVar) (Just (JSApp (JSAccessor "slice" (JSVar (Ident varName))) [JSNumericLiteral (Left index)])) : js)
117 go done rest index (binder:bs) = do
141 go done rest index (binder:bs) = do
118 elVar <- fresh
142 elVar <- fresh
119 done' <- go done rest (index + 1) bs
143 done' <- go done rest (index + 1) bs
120− js <- binderToJs elVar done' binder
144+ js <- binderToJs m elVar done' binder
121− return (JSVariableIntroduction (Ident elVar) (JSIndexer (JSNumericLiteral (Left index)) (JSVar (Ident varName))) : js)
145+ return (JSVariableIntroduction (Ident elVar) (Just (JSIndexer (JSNumericLiteral (Left index)) (JSVar (Ident varName)))) : js)
122−binderToJs varName done (NamedBinder ident binder) = do
146+binderToJs m varName done (NamedBinder ident binder) = do
123− js <- binderToJs varName done binder
147+ js <- binderToJs m varName done binder
124− return (JSVariableIntroduction ident (JSVar (Ident varName)) : js)
148+ return (JSVariableIntroduction ident (Just (JSVar (Ident varName))) : js)
125−binderToJs varName done (GuardedBinder cond binder) = binderToJs varName done' binder
149+binderToJs m varName done (GuardedBinder cond binder) = binderToJs m varName done' binder
127− done' = [JSIfElse (valueToJs cond) (JSBlock done) Nothing]
151+ done' = [JSIfElse (valueToJs m cond) (JSBlock done) Nothing]
129−statementToJs :: Statement -> JS
153+statementToJs :: ModulePath -> Statement -> JS
130−statementToJs (VariableIntroduction ident value) = JSVariableIntroduction ident (valueToJs value)
154+statementToJs m (VariableIntroduction ident value) = JSVariableIntroduction ident (Just (valueToJs m value))
131−statementToJs (Assignment target value) = JSAssignment target (valueToJs value)
155+statementToJs m (Assignment target value) = JSAssignment (JSAssignVariable target) (valueToJs m value)
132−statementToJs (While cond sts) = JSWhile (valueToJs cond) (JSBlock (map statementToJs sts))
156+statementToJs m (While cond sts) = JSWhile (valueToJs m cond) (JSBlock (map (statementToJs m) sts))
133−statementToJs (For ident start end sts) = JSFor ident (valueToJs start) (valueToJs end) (JSBlock (map statementToJs sts))
157+statementToJs m (For ident start end sts) = JSFor ident (valueToJs m start) (valueToJs m end) (JSBlock (map (statementToJs m) sts))
134−statementToJs (ForEach ident arr sts) = JSApp (JSAccessor "forEach" (valueToJs arr)) [JSFunction Nothing [ident] (JSBlock (map statementToJs sts))]
158+statementToJs m (ForEach ident arr sts) = JSApp (JSAccessor "forEach" (valueToJs m arr)) [JSFunction Nothing [ident] (JSBlock (map (statementToJs m) sts))]
135−statementToJs (If ifst) = ifToJs ifst
159+statementToJs m (If ifst) = ifToJs ifst
137 ifToJs :: IfStatement -> JS
161 ifToJs :: IfStatement -> JS
138− ifToJs (IfStatement cond thens elses) = JSIfElse (valueToJs cond) (JSBlock (map statementToJs thens)) (fmap elseToJs elses)
162+ ifToJs (IfStatement cond thens elses) = JSIfElse (valueToJs m cond) (JSBlock (map (statementToJs m) thens)) (fmap elseToJs elses)
139 elseToJs :: ElseStatement -> JS
163 elseToJs :: ElseStatement -> JS
140− elseToJs (Else sts) = JSBlock (map statementToJs sts)
164+ elseToJs (Else sts) = JSBlock (map (statementToJs m) sts)
141 elseToJs (ElseIf ifst) = ifToJs ifst
165 elseToJs (ElseIf ifst) = ifToJs ifst
142−statementToJs (Return value) = JSReturn (valueToJs value)
166+statementToJs m (Return value) = JSReturn (valueToJs m value)