@@ -41,11 +41,12 @@ import Language.PureScript.Options
41import Language.PureScript.CodeGen.JS.AST as AST
41import Language.PureScript.CodeGen.JS.AST as AST
42import Language.PureScript.Types
42import Language.PureScript.Types
43import Language.PureScript.CodeGen.Optimize
43import Language.PureScript.CodeGen.Optimize
44−import Language.PureScript.CodeGen.Common (identToJs)
44+import Language.PureScript.CodeGen.Common
45import Language.PureScript.TypeChecker.Monad (canonicalizeDataConstructor)
45import Language.PureScript.TypeChecker.Monad (canonicalizeDataConstructor)
48−-- Generate code in the simplified Javascript intermediate representation for all declarations in a module
48+-- Generate code in the simplified Javascript intermediate representation for all declarations in a
50moduleToJs :: Options -> Module -> Environment -> [JS]
51moduleToJs :: Options -> Module -> Environment -> [JS]
51moduleToJs opts (Module pname@(ProperName name) decls) env =
52moduleToJs opts (Module pname@(ProperName name) decls) env =
@@ -85,16 +86,36 @@ declToJs _ mp (ExternDeclaration importTy ident (Just js) _) _ =
85 Just $ js : setProperty ident (var ident) mp
86 Just $ js : setProperty ident (var ident) mp
86declToJs _ _ _ _ = Nothing
87declToJs _ _ _ _ = Nothing
90+-- Generate code in the simplified Javascript intermediate representation for setting the property
88setProperty :: Ident -> JS -> ModuleName -> [JS]
93setProperty :: Ident -> JS -> ModuleName -> [JS]
89setProperty ident@(Op op) val (ModuleName (ProperName moduleName)) =
94setProperty ident@(Op op) val (ModuleName (ProperName moduleName)) =
90− [ JSAssignment (JSAccessor (identToJs ident) (JSVar moduleName)) val
95+ [ JSAssignment (accessor ident (JSVar moduleName)) val
91− , JSAssignment (JSIndexer (JSStringLiteral op) (JSVar moduleName)) (JSAccessor (identToJs ident) (JSVar moduleName)) ]
96+ , JSAssignment (JSIndexer (JSStringLiteral op) (JSVar moduleName)) (accessor ident (JSVar moduleName)) ]
92setProperty ident val (ModuleName (ProperName moduleName)) =
97setProperty ident val (ModuleName (ProperName moduleName)) =
93− [ JSAssignment (JSAccessor (identToJs ident) (JSVar moduleName)) val ]
98+ [ JSAssignment (accessor ident (JSVar moduleName)) val ]
101+-- Generate code in the simplified Javascript intermediate representation for a variable based on a
102+-- PureScript identifier.
95var :: Ident -> JS
104var :: Ident -> JS
96var = JSVar . identToJs
105var = JSVar . identToJs
108+-- Generate code in the simplified Javascript intermediate representation for an accessor based on
109+-- a PureScript identifier. If the name is not valid in Javascript (symbol based, reserved name) an
110+-- indexer is returned.
112+accessor :: Ident -> JS -> JS
113+accessor (Ident name) | nameIsJsReserved name = JSIndexer (JSStringLiteral name)
114+accessor ident = JSAccessor (identToJs ident)
117+-- Generate code in the simplified Javascript intermediate representation for a value or expression.
98valueToJs :: Options -> ModuleName -> Environment -> Value -> JS
119valueToJs :: Options -> ModuleName -> Environment -> Value -> JS
99valueToJs _ _ _ (NumericLiteral n) = JSNumericLiteral n
120valueToJs _ _ _ (NumericLiteral n) = JSNumericLiteral n
100valueToJs _ _ _ (StringLiteral s) = JSStringLiteral s
121valueToJs _ _ _ (StringLiteral s) = JSStringLiteral s
@@ -104,21 +125,31 @@ valueToJs opts m e (ObjectLiteral ps) = JSObjectLiteral (map (second (valueToJs
104valueToJs opts m e (ObjectUpdate o ps) = JSApp (JSAccessor "extend" (JSVar "Object")) [ valueToJs opts m e o, JSObjectLiteral (map (second (valueToJs opts m e)) ps)]
125valueToJs opts m e (ObjectUpdate o ps) = JSApp (JSAccessor "extend" (JSVar "Object")) [ valueToJs opts m e o, JSObjectLiteral (map (second (valueToJs opts m e)) ps)]
105valueToJs _ m e (Constructor (Qualified Nothing name)) =
126valueToJs _ m e (Constructor (Qualified Nothing name)) =
106 case M.lookup (m, name) (dataConstructors e) of
127 case M.lookup (m, name) (dataConstructors e) of
107− Just (_, Alias aliasModule aliasIdent) -> qualifiedToJS identToJs (Qualified (Just aliasModule) aliasIdent)
128+ Just (_, Alias aliasModule aliasIdent) -> qualifiedToJS id (Qualified (Just aliasModule) aliasIdent)
108 _ -> JSVar . runProperName $ name
129 _ -> JSVar . runProperName $ name
109−valueToJs _ _ _ (Constructor name) = qualifiedToJS runProperName name
130+valueToJs _ _ _ (Constructor name) = qualifiedToJS (Ident . runProperName) name
110valueToJs opts m e (Block sts) = JSApp (JSFunction Nothing [] (JSBlock (map (statementToJs opts m e) sts))) []
131valueToJs opts m e (Block sts) = JSApp (JSFunction Nothing [] (JSBlock (map (statementToJs opts m e) sts))) []
111valueToJs opts m e (Case values binders) = bindersToJs opts m e binders (map (valueToJs opts m e) values)
132valueToJs opts m e (Case values binders) = bindersToJs opts m e binders (map (valueToJs opts m e) values)
112valueToJs opts m e (IfThenElse cond th el) = JSConditional (valueToJs opts m e cond) (valueToJs opts m e th) (valueToJs opts m e el)
133valueToJs opts m e (IfThenElse cond th el) = JSConditional (valueToJs opts m e cond) (valueToJs opts m e th) (valueToJs opts m e el)
113valueToJs opts m e (Accessor prop val) = JSAccessor prop (valueToJs opts m e val)
134valueToJs opts m e (Accessor prop val) = JSAccessor prop (valueToJs opts m e val)
114valueToJs opts m e (App val arg) = JSApp (valueToJs opts m e val) [valueToJs opts m e arg]
135valueToJs opts m e (App val arg) = JSApp (valueToJs opts m e val) [valueToJs opts m e arg]
115−valueToJs opts m e (Abs arg val) = JSFunction Nothing [identToJs arg] (JSBlock [JSReturn (valueToJs opts m e val)])
136+valueToJs opts m e (Abs arg val) = JSFunction Nothing [identToJs arg] (JSBlock [JSReturn (valueToJs opts m (bindName m arg e) val)])
116valueToJs opts m e (TypedValue _ (Abs arg val) ty) | optionsPerformRuntimeTypeChecks opts = let arg' = identToJs arg in JSFunction Nothing [arg'] (JSBlock $ runtimeTypeChecks arg' ty ++ [JSReturn (valueToJs opts m e val)])
137valueToJs opts m e (TypedValue _ (Abs arg val) ty) | optionsPerformRuntimeTypeChecks opts = let arg' = identToJs arg in JSFunction Nothing [arg'] (JSBlock $ runtimeTypeChecks arg' ty ++ [JSReturn (valueToJs opts m e val)])
117valueToJs _ m e (Var ident) = varToJs m e ident
138valueToJs _ m e (Var ident) = varToJs m e ident
118valueToJs opts m e (TypedValue _ val _) = valueToJs opts m e val
139valueToJs opts m e (TypedValue _ val _) = valueToJs opts m e val
119valueToJs _ _ _ (TypeClassDictionary _ _) = error "Type class dictionary was not replaced"
140valueToJs _ _ _ (TypeClassDictionary _ _) = error "Type class dictionary was not replaced"
120valueToJs _ _ _ _ = error "Invalid argument to valueToJs"
141valueToJs _ _ _ _ = error "Invalid argument to valueToJs"
144+-- Temporarily extends the environment to include a local variable name introduced by a lambda
147+bindName :: ModuleName -> Ident -> Environment -> Environment
148+bindName m ident env = env { names = M.insert (m, ident) (error "Temporary lambda variable type was read", LocalVariable) $ names env }
151+-- Generate code in the simplified Javascript intermediate representation for runtime type checks.
122runtimeTypeChecks :: String -> Type -> [JS]
153runtimeTypeChecks :: String -> Type -> [JS]
123runtimeTypeChecks arg ty =
154runtimeTypeChecks arg ty =
@@ -148,6 +179,10 @@ runtimeTypeChecks arg ty =
148 arrayCheck :: JS -> JS
179 arrayCheck :: JS -> JS
149 arrayCheck js = JSIfElse (JSUnary Not (JSApp (JSAccessor "isArray" (JSVar "Array")) [js])) (JSBlock [JSThrow (JSStringLiteral "Array expected")]) Nothing
180 arrayCheck js = JSIfElse (JSUnary Not (JSApp (JSAccessor "isArray" (JSVar "Array")) [js])) (JSBlock [JSThrow (JSStringLiteral "Array expected")]) Nothing
183+-- Generate code in the simplified Javascript intermediate representation for a reference to a
151varToJs :: ModuleName -> Environment -> Qualified Ident -> JS
186varToJs :: ModuleName -> Environment -> Qualified Ident -> JS
152varToJs m e qual@(Qualified _ ident) = go qual
187varToJs m e qual@(Qualified _ ident) = go qual
@@ -156,18 +191,25 @@ varToJs m e qual@(Qualified _ ident) = go qual
156 Just (_, Alias aliasModule aliasIdent) -> go (Qualified (Just aliasModule) aliasIdent)
191 Just (_, Alias aliasModule aliasIdent) -> go (Qualified (Just aliasModule) aliasIdent)
157 _ -> case qual of
192 _ -> case qual of
158 Qualified Nothing _ -> var ident
193 Qualified Nothing _ -> var ident
159− Qualified (Just (ModuleName (ProperName mn))) (Op op) -> JSIndexer (JSStringLiteral op) (JSVar mn)
160− _ -> qualifiedToJS identToJs qual
194+ _ -> qualifiedToJS id qual
161 isExtern (Extern ForeignImport) = True
195 isExtern (Extern ForeignImport) = True
162 isExtern (Alias m' ident') = case M.lookup (m', ident') (names e) of
196 isExtern (Alias m' ident') = case M.lookup (m', ident') (names e) of
163 Just (_, ty') -> isExtern ty'
197 Just (_, ty') -> isExtern ty'
164 Nothing -> error "Undefined alias in varToJs"
198 Nothing -> error "Undefined alias in varToJs"
165 isExtern _ = False
199 isExtern _ = False
202+-- Generate code in the simplified Javascript intermediate representation for a reference to a
203+-- variable that may have a qualified name.
167−qualifiedToJS :: (a -> String) -> Qualified a -> JS
205+qualifiedToJS :: (a -> Ident) -> Qualified a -> JS
168−qualifiedToJS f (Qualified (Just (ModuleName (ProperName m))) a) = JSAccessor (f a) (JSVar m)
206+qualifiedToJS f (Qualified (Just (ModuleName (ProperName m))) a) = accessor (f a) (JSVar m)
169−qualifiedToJS f (Qualified Nothing a) = JSVar (f a)
207+qualifiedToJS f (Qualified Nothing a) = JSVar $ identToJs (f a)
210+-- Generate code in the simplified Javascript intermediate representation for pattern match binders
171bindersToJs :: Options -> ModuleName -> Environment -> [([Binder], Maybe Guard, Value)] -> [JS] -> JS
213bindersToJs :: Options -> ModuleName -> Environment -> [([Binder], Maybe Guard, Value)] -> [JS] -> JS
172bindersToJs opts m e binders vals = runGen (map identToJs (unusedNames (binders, vals))) $ do
214bindersToJs opts m e binders vals = runGen (map identToJs (unusedNames (binders, vals))) $ do
173 valNames <- replicateM (length vals) fresh
215 valNames <- replicateM (length vals) fresh
@@ -183,6 +225,10 @@ bindersToJs opts m e binders vals = runGen (map identToJs (unusedNames (binders,
183 binderToJs m e v done'' b
225 binderToJs m e v done'' b
184 go _ _ _ _ = error "Invalid arguments to bindersToJs"
226 go _ _ _ _ = error "Invalid arguments to bindersToJs"
229+-- Generate code in the simplified Javascript intermediate representation for a pattern match
186binderToJs :: ModuleName -> Environment -> String -> [JS] -> Binder -> Gen [JS]
232binderToJs :: ModuleName -> Environment -> String -> [JS] -> Binder -> Gen [JS]
187binderToJs _ _ _ done NullBinder = return done
233binderToJs _ _ _ done NullBinder = return done
188binderToJs _ _ varName done (StringBinder str) =
234binderToJs _ _ varName done (StringBinder str) =
@@ -246,6 +292,10 @@ binderToJs m e varName done (NamedBinder ident binder) = do
246 js <- binderToJs m e varName done binder
292 js <- binderToJs m e varName done binder
247 return (JSVariableIntroduction (identToJs ident) (Just (JSVar varName)) : js)
293 return (JSVariableIntroduction (identToJs ident) (Just (JSVar varName)) : js)
296+-- Checks whether a data constructor is the only constructor for that type, used to simplify the
297+-- check when generating code for binders.
249isOnlyConstructor :: ModuleName -> Environment -> Qualified ProperName -> Bool
299isOnlyConstructor :: ModuleName -> Environment -> Qualified ProperName -> Bool
250isOnlyConstructor m e ctor =
300isOnlyConstructor m e ctor =
251 let (ty, _) = fromMaybe (error "Data constructor not found") $ qualify m ctor `M.lookup` dataConstructors e
301 let (ty, _) = fromMaybe (error "Data constructor not found") $ qualify m ctor `M.lookup` dataConstructors e
@@ -258,6 +308,10 @@ isOnlyConstructor m e ctor =
258 typeConstructor (TypeApp ty _) = typeConstructor ty
308 typeConstructor (TypeApp ty _) = typeConstructor ty
259 typeConstructor fn = error $ "Invalid arguments to typeConstructor: " ++ show fn
309 typeConstructor fn = error $ "Invalid arguments to typeConstructor: " ++ show fn
312+-- Generate code in the simplified Javascript intermediate representation for a statement in a
261statementToJs :: Options -> ModuleName -> Environment -> Statement -> JS
315statementToJs :: Options -> ModuleName -> Environment -> Statement -> JS
262statementToJs opts m e (VariableIntroduction ident value) = JSVariableIntroduction (identToJs ident) (Just (valueToJs opts m e value))
316statementToJs opts m e (VariableIntroduction ident value) = JSVariableIntroduction (identToJs ident) (Just (valueToJs opts m e value))
263statementToJs opts m e (Assignment target value) = JSAssignment (JSVar (identToJs target)) (valueToJs opts m e value)
317statementToJs opts m e (Assignment target value) = JSAssignment (JSVar (identToJs target)) (valueToJs opts m e value)