@@ -30,31 +30,33 @@ import Language.PureScript.Scope
30import Language.PureScript.Declarations
30import Language.PureScript.Declarations
31import Language.PureScript.Pretty.Common
31import Language.PureScript.Pretty.Common
32import Language.PureScript.CodeGen.Monad
32import Language.PureScript.CodeGen.Monad
33+import Language.PureScript.Options
33import Language.PureScript.CodeGen.JS.AST as AST
34import Language.PureScript.CodeGen.JS.AST as AST
34import Language.PureScript.TypeChecker.Monad (NameKind(..))
35import Language.PureScript.TypeChecker.Monad (NameKind(..))
36+import Language.PureScript.Types
36−moduleToJs :: Module -> Environment -> [JS]
38+moduleToJs :: Options -> Module -> Environment -> [JS]
37−moduleToJs (Module pname@(ProperName name) decls) env =
39+moduleToJs opts (Module pname@(ProperName name) decls) env =
38 [ JSVariableIntroduction (Ident name) Nothing
40 [ JSVariableIntroduction (Ident name) Nothing
39 , JSApp (JSFunction Nothing [Ident name]
41 , JSApp (JSFunction Nothing [Ident name]
40− (JSBlock (concat $ mapMaybe (\decl -> declToJs (ModuleName pname) decl env) decls)))
42+ (JSBlock (concat $ mapMaybe (\decl -> declToJs opts (ModuleName pname) decl env) decls)))
41 [JSAssignment (JSAssignVariable (Ident name))
43 [JSAssignment (JSAssignVariable (Ident name))
42 (JSBinary Or (JSVar (Ident name)) (JSObjectLiteral []))]
44 (JSBinary Or (JSVar (Ident name)) (JSObjectLiteral []))]
45−declToJs :: ModuleName -> Declaration -> Environment -> Maybe [JS]
47+declToJs :: Options -> ModuleName -> Declaration -> Environment -> Maybe [JS]
46−declToJs mp (ValueDeclaration ident _ _ val) e =
48+declToJs opts mp (ValueDeclaration ident _ _ val) e =
47− Just [ JSVariableIntroduction ident (Just (valueToJs mp e val)),
49+ Just [ JSVariableIntroduction ident (Just (valueToJs opts mp e val)),
48 setProperty (identToJs ident) (JSVar ident) mp ]
50 setProperty (identToJs ident) (JSVar ident) mp ]
49−declToJs mp (BindingGroupDeclaration vals) e =
51+declToJs opts mp (BindingGroupDeclaration vals) e =
50 Just $ concatMap (\(ident, val) ->
52 Just $ concatMap (\(ident, val) ->
51− [ JSVariableIntroduction ident (Just (valueToJs mp e val)),
53+ [ JSVariableIntroduction ident (Just (valueToJs opts mp e val)),
52 setProperty (identToJs ident) (JSVar ident) mp ]
54 setProperty (identToJs ident) (JSVar ident) mp ]
54−declToJs mp (ExternMemberDeclaration member ident _) _ =
56+declToJs _ mp (ExternMemberDeclaration member ident _) _ =
55 Just [ JSFunction (Just ident) [Ident "value"] (JSBlock [JSReturn (JSAccessor member (JSVar (Ident "value")))]),
57 Just [ JSFunction (Just ident) [Ident "value"] (JSBlock [JSReturn (JSAccessor member (JSVar (Ident "value")))]),
56 setProperty (show ident) (JSVar ident) mp ]
58 setProperty (show ident) (JSVar ident) mp ]
57−declToJs mp (DataDeclaration _ _ ctors) _ =
59+declToJs _ mp (DataDeclaration _ _ ctors) _ =
58 Just $ flip concatMap ctors $ \(pn@(ProperName ctor), maybeTy) ->
60 Just $ flip concatMap ctors $ \(pn@(ProperName ctor), maybeTy) ->
@@ -65,31 +67,61 @@ declToJs mp (DataDeclaration _ _ ctors) _ =
65 (JSObjectLiteral [ ("ctor", JSStringLiteral (show (Qualified (Just mp) pn)))
67 (JSObjectLiteral [ ("ctor", JSStringLiteral (show (Qualified (Just mp) pn)))
66 , ("value", JSVar (Ident "value")) ])])
68 , ("value", JSVar (Ident "value")) ])])
67 in [ ctorJs, setProperty ctor (JSVar (Ident ctor)) mp ]
69 in [ ctorJs, setProperty ctor (JSVar (Ident ctor)) mp ]
68−declToJs _ _ _ = Nothing
70+declToJs _ _ _ _ = Nothing
70setProperty :: String -> JS -> ModuleName -> JS
72setProperty :: String -> JS -> ModuleName -> JS
71setProperty prop val (ModuleName (ProperName moduleName)) = JSAssignment (JSAssignProperty prop (JSAssignVariable (Ident moduleName))) val
73setProperty prop val (ModuleName (ProperName moduleName)) = JSAssignment (JSAssignProperty prop (JSAssignVariable (Ident moduleName))) val
73−valueToJs :: ModuleName -> Environment -> Value -> JS
75+valueToJs :: Options -> ModuleName -> Environment -> Value -> JS
74−valueToJs _ _ (NumericLiteral n) = JSNumericLiteral n
76+valueToJs _ _ _ (NumericLiteral n) = JSNumericLiteral n
75−valueToJs _ _ (StringLiteral s) = JSStringLiteral s
77+valueToJs _ _ _ (StringLiteral s) = JSStringLiteral s
76−valueToJs _ _ (BooleanLiteral b) = JSBooleanLiteral b
78+valueToJs _ _ _ (BooleanLiteral b) = JSBooleanLiteral b
77−valueToJs m e (ArrayLiteral xs) = JSArrayLiteral (map (valueToJs m e) xs)
79+valueToJs opts m e (ArrayLiteral xs) = JSArrayLiteral (map (valueToJs opts m e) xs)
78−valueToJs m e (ObjectLiteral ps) = JSObjectLiteral (map (second (valueToJs m e)) ps)
80+valueToJs opts m e (ObjectLiteral ps) = JSObjectLiteral (map (second (valueToJs opts m e)) ps)
79−valueToJs m e (ObjectUpdate o ps) = JSApp (JSAccessor "extend" (JSVar (Ident "Object"))) [ valueToJs m e o, JSObjectLiteral (map (second (valueToJs m e)) ps)]
81+valueToJs opts m e (ObjectUpdate o ps) = JSApp (JSAccessor "extend" (JSVar (Ident "Object"))) [ valueToJs opts m e o, JSObjectLiteral (map (second (valueToJs opts m e)) ps)]
80−valueToJs _ _ (Constructor name) = qualifiedToJS runProperName name
82+valueToJs _ _ _ (Constructor name) = qualifiedToJS runProperName name
81−valueToJs m e (Block sts) = JSApp (JSFunction Nothing [] (JSBlock (map (statementToJs m e) sts))) []
83+valueToJs opts m e (Block sts) = JSApp (JSFunction Nothing [] (JSBlock (map (statementToJs opts m e) sts))) []
82−valueToJs m e (Case values binders) = runGen (bindersToJs m e binders (map (valueToJs m e) values))
84+valueToJs opts m e (Case values binders) = runGen (bindersToJs opts m e binders (map (valueToJs opts m e) values))
83−valueToJs m e (IfThenElse cond th el) = JSConditional (valueToJs m e cond) (valueToJs m e th) (valueToJs m e el)
85+valueToJs opts m e (IfThenElse cond th el) = JSConditional (valueToJs opts m e cond) (valueToJs opts m e th) (valueToJs opts m e el)
84−valueToJs m e (Accessor prop val) = JSAccessor prop (valueToJs m e val)
86+valueToJs opts m e (Accessor prop val) = JSAccessor prop (valueToJs opts m e val)
85−valueToJs m e (Indexer index val) = JSIndexer (valueToJs m e index) (valueToJs m e val)
87+valueToJs opts m e (Indexer index val) = JSIndexer (valueToJs opts m e index) (valueToJs opts m e val)
86−valueToJs m e (App val args) = JSApp (valueToJs m e val) (map (valueToJs m e) args)
88+valueToJs opts m e (App val args) = JSApp (valueToJs opts m e val) (map (valueToJs opts m e) args)
89+valueToJs opts m e (Abs args val) = JSFunction Nothing args (JSBlock [JSReturn (valueToJs opts m e val)])
87−valueToJs m e (Abs args val) = JSFunction Nothing args (JSBlock [JSReturn (valueToJs m e val)])
90+valueToJs opts m e (TypedValue (Abs args val) ty) | optionsPerformRuntimeTypeChecks opts = JSFunction Nothing args (JSBlock $ runtimeTypeChecks args ty ++ [JSReturn (valueToJs opts m e val)])
88−valueToJs m e (Unary op val) = JSUnary op (valueToJs m e val)
91+valueToJs opts m e (Unary op val) = JSUnary op (valueToJs opts m e val)
89−valueToJs m e (Binary op v1 v2) = JSBinary op (valueToJs m e v1) (valueToJs m e v2)
92+valueToJs opts m e (Binary op v1 v2) = JSBinary op (valueToJs opts m e v1) (valueToJs opts m e v2)
90−valueToJs m e (Var ident) = varToJs m e ident
93+valueToJs _ m e (Var ident) = varToJs m e ident
91−valueToJs m e (TypedValue val _) = valueToJs m e val
94+valueToJs opts m e (TypedValue val _) = valueToJs opts m e val
92−valueToJs _ _ _ = error "Invalid argument to valueToJs"
95+valueToJs _ _ _ _ = error "Invalid argument to valueToJs"
97+runtimeTypeChecks :: [Ident] -> Type -> [JS]
98+runtimeTypeChecks args ty =
100+ argTys = getFunctionArgumentTypes ty
102+ concat $ zipWith argumentCheck (map JSVar args) argTys
104+ getFunctionArgumentTypes :: Type -> [Type]
105+ getFunctionArgumentTypes (Function funArgs _) = funArgs
106+ getFunctionArgumentTypes (ForAll _ ty') = getFunctionArgumentTypes ty'
107+ getFunctionArgumentTypes _ = []
108+ argumentCheck :: JS -> Type -> [JS]
109+ argumentCheck val Number = [typeCheck val "number"]
110+ argumentCheck val String = [typeCheck val "string"]
111+ argumentCheck val Boolean = [typeCheck val "boolean"]
112+ argumentCheck val (Array _) = [arrayCheck val]
113+ argumentCheck val (Object row) =
115+ (pairs, _) = rowToList row
117+ typeCheck val "object" : concatMap (\(prop, ty') -> argumentCheck (JSAccessor prop val) ty') pairs
118+ argumentCheck val (Function _ _) = [typeCheck val "function"]
119+ argumentCheck val (ForAll _ ty') = argumentCheck val ty'
120+ argumentCheck _ _ = []
121+ typeCheck :: JS -> String -> JS
122+ typeCheck js ty' = JSIfElse (JSBinary NotEqualTo (JSTypeOf js) (JSStringLiteral ty')) (JSBlock [JSThrow (JSStringLiteral $ ty' ++ " expected")]) Nothing
123+ arrayCheck :: JS -> JS
124+ arrayCheck js = JSIfElse (JSUnary Not (JSApp (JSAccessor "isArray" (JSVar (Ident "Array"))) [js])) (JSBlock [JSThrow (JSStringLiteral "Array expected")]) Nothing
94varToJs :: ModuleName -> Environment -> Qualified Ident -> JS
126varToJs :: ModuleName -> Environment -> Qualified Ident -> JS
95varToJs m e qual@(Qualified _ ident) = case M.lookup (qualify m qual) (names e) of
127varToJs m e qual@(Qualified _ ident) = case M.lookup (qualify m qual) (names e) of
@@ -107,17 +139,17 @@ qualifiedToJS :: (a -> String) -> Qualified a -> JS
107qualifiedToJS f (Qualified (Just (ModuleName (ProperName m))) a) = JSAccessor (f a) (JSVar (Ident m))
139qualifiedToJS f (Qualified (Just (ModuleName (ProperName m))) a) = JSAccessor (f a) (JSVar (Ident m))
108qualifiedToJS f (Qualified Nothing a) = JSVar (Ident (f a))
140qualifiedToJS f (Qualified Nothing a) = JSVar (Ident (f a))
110−bindersToJs :: ModuleName -> Environment -> [([Binder], Maybe Guard, Value)] -> [JS] -> Gen JS
142+bindersToJs :: Options -> ModuleName -> Environment -> [([Binder], Maybe Guard, Value)] -> [JS] -> Gen JS
111−bindersToJs m e binders vals = do
143+bindersToJs opts m e binders vals = do
112 setNextName $ firstUnusedName (binders, vals)
144 setNextName $ firstUnusedName (binders, vals)
113 valNames <- replicateM (length vals) fresh
145 valNames <- replicateM (length vals) fresh
114− jss <- forM binders $ \(bs, grd, result) -> go valNames [JSReturn (valueToJs m e result)] bs grd
146+ jss <- forM binders $ \(bs, grd, result) -> go valNames [JSReturn (valueToJs opts m e result)] bs grd
115 return $ JSApp (JSFunction Nothing (map Ident valNames) (JSBlock (concat jss ++ [JSThrow (JSStringLiteral "Failed pattern match")])))
147 return $ JSApp (JSFunction Nothing (map Ident valNames) (JSBlock (concat jss ++ [JSThrow (JSStringLiteral "Failed pattern match")])))
118 go :: [String] -> [JS] -> [Binder] -> Maybe Guard -> Gen [JS]
150 go :: [String] -> [JS] -> [Binder] -> Maybe Guard -> Gen [JS]
119 go _ done [] Nothing = return done
151 go _ done [] Nothing = return done
120− go _ done [] (Just cond) = return [JSIfElse (valueToJs m e cond) (JSBlock done) Nothing]
152+ go _ done [] (Just cond) = return [JSIfElse (valueToJs opts m e cond) (JSBlock done) Nothing]
121 go (v:vs) done' (b:bs) grd = do
153 go (v:vs) done' (b:bs) grd = do
122 done'' <- go vs done' bs grd
154 done'' <- go vs done' bs grd
123 binderToJs m e v done'' b
155 binderToJs m e v done'' b
@@ -175,16 +207,16 @@ binderToJs m e varName done (NamedBinder ident binder) = do
175 js <- binderToJs m e varName done binder
207 js <- binderToJs m e varName done binder
176 return (JSVariableIntroduction ident (Just (JSVar (Ident varName))) : js)
208 return (JSVariableIntroduction ident (Just (JSVar (Ident varName))) : js)
178−statementToJs :: ModuleName -> Environment -> Statement -> JS
210+statementToJs :: Options -> ModuleName -> Environment -> Statement -> JS
179−statementToJs m e (VariableIntroduction ident value) = JSVariableIntroduction ident (Just (valueToJs m e value))
211+statementToJs opts m e (VariableIntroduction ident value) = JSVariableIntroduction ident (Just (valueToJs opts m e value))
180−statementToJs m e (Assignment target value) = JSAssignment (JSAssignVariable target) (valueToJs m e value)
212+statementToJs opts m e (Assignment target value) = JSAssignment (JSAssignVariable target) (valueToJs opts m e value)
181−statementToJs m e (While cond sts) = JSWhile (valueToJs m e cond) (JSBlock (map (statementToJs m e) sts))
213+statementToJs opts m e (While cond sts) = JSWhile (valueToJs opts m e cond) (JSBlock (map (statementToJs opts m e) sts))
182−statementToJs m e (For ident start end sts) = JSFor ident (valueToJs m e start) (valueToJs m e end) (JSBlock (map (statementToJs m e) sts))
214+statementToJs opts m e (For ident start end sts) = JSFor ident (valueToJs opts m e start) (valueToJs opts m e end) (JSBlock (map (statementToJs opts m e) sts))
183−statementToJs m e (If ifst) = ifToJs ifst
215+statementToJs opts m e (If ifst) = ifToJs ifst
185 ifToJs :: IfStatement -> JS
217 ifToJs :: IfStatement -> JS
186− ifToJs (IfStatement cond thens elses) = JSIfElse (valueToJs m e cond) (JSBlock (map (statementToJs m e) thens)) (fmap elseToJs elses)
218+ ifToJs (IfStatement cond thens elses) = JSIfElse (valueToJs opts m e cond) (JSBlock (map (statementToJs opts m e) thens)) (fmap elseToJs elses)
187 elseToJs :: ElseStatement -> JS
219 elseToJs :: ElseStatement -> JS
188− elseToJs (Else sts) = JSBlock (map (statementToJs m e) sts)
220+ elseToJs (Else sts) = JSBlock (map (statementToJs opts m e) sts)
189 elseToJs (ElseIf elif) = ifToJs elif
221 elseToJs (ElseIf elif) = ifToJs elif
190−statementToJs m e (Return value) = JSReturn (valueToJs m e value)
222+statementToJs opts m e (Return value) = JSReturn (valueToJs opts m e value)