@@ -12,344 +12,10 @@
13-----------------------------------------------------------------------------
13-----------------------------------------------------------------------------
15−{-# LANGUAGE GADTs, GeneralizedNewtypeDeriving #-}
17module PureScript.CodeGen (
15module PureScript.CodeGen (
18− declToJs,
16+ module PureScript.CodeGen.JS,
19− externToJs
17+ module PureScript.CodeGen.Externs
22−import Data.Maybe (fromMaybe)
20+import PureScript.CodeGen.JS
23−import Data.List (nub, intersperse, intercalate)
21+import PureScript.CodeGen.Externs
24−import Data.Function (fix)
25−import Control.Monad.State
26−import Control.Applicative (Applicative(..), Alternative(..))
27−import qualified Control.Category as C
28−import Control.Category ((>>>))
29−import qualified Control.Arrow as A
30−import Control.Arrow ((***))
32−import PureScript.Values
33−import PureScript.Types
34−import PureScript.Declarations
36−-- First Order Patterns
38−newtype Pattern a b = Pattern { runPattern :: A.Kleisli Maybe a b } deriving (C.Category, A.Arrow)
40−pattern :: Pattern a b -> a -> Maybe b
41−pattern = A.runKleisli . runPattern
43−instance Functor (Pattern a) where
44− fmap f p = Pattern $ A.Kleisli $ fmap f . pattern p
46−instance Applicative (Pattern a) where
47− pure = Pattern . A.Kleisli . const . pure
48− f <*> x = Pattern . A.Kleisli $ \a -> pattern f a <*> pattern x a
50−instance Alternative (Pattern a) where
51− empty = Pattern $ A.Kleisli $ \a -> empty
52− (Pattern (A.Kleisli p)) <|> (Pattern (A.Kleisli q)) = Pattern $ A.Kleisli $ \a -> p a <|> q a
54−parens :: String -> String
55−parens s = ('(':s) ++ ")"
57−chainl :: Pattern a (a, a) -> (r -> r -> r) -> Pattern a r -> Pattern a r
58−chainl split f p = fix $ \c -> (split >>> (c *** p) >>> A.arr (uncurry f)) <|> p
60−chainr :: Pattern a (a, a) -> (r -> r -> r) -> Pattern a r -> Pattern a r
61−chainr split f p = fix $ \c -> (split >>> (p *** c) >>> A.arr (uncurry f)) <|> p
63−wrap :: Pattern a (s, a) -> (s -> r -> r) -> Pattern a r -> Pattern a r
64−wrap split f p = fix $ \c -> (split >>> (C.id *** c) >>> A.arr (uncurry f)) <|> p
66−split :: Pattern a (s, t) -> (s -> t -> r) -> Pattern a r -> Pattern a r
67−split s f p = (s >>> A.arr (uncurry f)) <|> p
69−data OperatorTable a r = OperatorTable { runOperatorTable :: [Operator a r] }
71−data Operator a r where
72− AssocL :: Pattern a (a, a) -> (r -> r -> r) -> Operator a r
73− AssocR :: Pattern a (a, a) -> (r -> r -> r) -> Operator a r
74− Wrap :: Pattern a (s, a) -> (s -> r -> r) -> Operator a r
75− Split :: Pattern a (s, t) -> (s -> t -> r) -> Operator a r
77−buildPrettyPrinter :: OperatorTable a r -> Pattern a r -> Pattern a r
78−buildPrettyPrinter table p = foldl (\p' op ->
80− AssocL pat g -> chainl pat g p'
81− AssocR pat g -> chainr pat g p'
82− Wrap pat g -> wrap pat g p'
83− Split pat g -> split pat g p'
84− ) p $ runOperatorTable table
86−-- Variable Name Generation
88−newtype Gen a = Gen { unGen :: State Int a } deriving (Functor, Monad, MonadState Int)
91−runGen = flip evalState 0 . unGen
97− return $ "_" ++ show n
101−declToJs :: Declaration -> Maybe String
102−declToJs (ValueDeclaration name val) = Just $ "var " ++ name ++ " = " ++ valueToJs val ++ ";"
103−declToJs (DataDeclaration dcs@(DataConstructors { dataConstructors = ctors })) =
104− Just $ flip concatMap ctors $ \(ctor, maybeTy) ->
106− Nothing -> "var " ++ ctor ++ " = { ctor: '" ++ ctor ++ "' };"
107− Just _ -> "var " ++ ctor ++ " = function (value) { return { ctor: '" ++ ctor ++ "', value: value }; };"
110−literals :: Pattern Value String
111−literals = Pattern $ A.Kleisli match
113− match (NumericLiteral n) = Just $ either show show n
114− match (StringLiteral s) = Just $ show s
115− match (BooleanLiteral True) = Just "true"
116− match (BooleanLiteral False) = Just "false"
117− match (ArrayLiteral xs) = Just $ "[" ++ intercalate "," (map valueToJs xs) ++ "]"
118− match (ObjectLiteral ps) = Just $ "{" ++ intercalate "," (map objectPropertyToJs ps) ++ "}"
119− match (Constructor name) = Just name
120− match (Block sts) = Just $ "(function () {" ++ intercalate ";" (map statementToJs sts) ++ "})()"
121− match (Case value binders) = Just $ "(" ++ runGen (bindersToJs binders) ++ ")(" ++ valueToJs value ++ ")"
123− bindersToJs :: [(Binder, Value)] -> Gen String
124− bindersToJs binders = do
126− jss <- flip mapM binders $ \(binder, result) -> do
127− let js = valueToJs result
128− binderToJs valName ("return " ++ js ++ ";") binder
129− return $ "function (" ++ valName ++ ") {" ++ concat jss ++ "throw \"Failed pattern match\"; }"
130− match (Var ident) = Just ident
133−accessor :: Pattern Value (String, Value)
134−accessor = Pattern $ A.Kleisli match
136− match (Accessor prop val) = Just (prop, val)
139−indexer :: Pattern Value (String, Value)
140−indexer = Pattern $ A.Kleisli match
142− match (Indexer index val) = Just (valueToJs index, val)
145−app :: Pattern Value (String, Value)
146−app = Pattern $ A.Kleisli match
148− match (App val args) = Just (intercalate "," (map valueToJs args), val)
151−lam :: Pattern Value ([String], Value)
152−lam = Pattern $ A.Kleisli match
154− match (Abs args val) = Just (args, val)
157−unary :: UnaryOperator -> String -> Operator Value String
158−unary op str = Wrap pattern (++)
160− pattern :: Pattern Value (String, Value)
161− pattern = Pattern $ A.Kleisli match
163− match (Unary op' val) | op' == op = Just (str, val)
166−binary :: BinaryOperator -> String -> Operator Value String
167−binary op str = AssocR pattern (\v1 v2 -> v1 ++ " " ++ str ++ " " ++ v2)
169− pattern :: Pattern Value (Value, Value)
170− pattern = Pattern $ A.Kleisli match
172− match (Binary op' v1 v2) | op' == op = Just (v1, v2)
175−valueToJs :: Value -> String
176−valueToJs = fromMaybe (error "Incomplete pattern") . pattern matchValue
178− matchValue :: Pattern Value String
179− matchValue = buildPrettyPrinter operators (literals <|> fmap parens matchValue)
180− operators :: OperatorTable Value String
182− OperatorTable $ [ Wrap accessor $ \prop val -> val ++ "." ++ prop
183− , Wrap indexer $ \index val -> val ++ "[" ++ index ++ "]"
184− , Wrap app $ \args val -> val ++ "(" ++ args ++ ")"
185− , Split lam $ \args val -> "function (" ++ intercalate "," args ++ ") { return " ++ valueToJs val ++ "; }"
186− , binary LessThan "<"
187− , binary LessThanOrEqualTo "<="
188− , binary GreaterThan ">"
189− , binary GreaterThanOrEqualTo ">="
191− , unary BitwiseNot "~"
193− , binary Multiply "*"
195− , binary Modulus "%"
196− , binary Concat "++"
198− , binary Subtract "-"
199− , binary ShiftLeft "<<"
200− , binary ShiftRight ">>"
201− , binary ZeroFillShiftRight ">>>"
202− , binary EqualTo "==="
203− , binary NotEqualTo "!=="
204− , binary BitwiseAnd "&"
205− , binary BitwiseXor "^"
206− , binary BitwiseOr "|"
211−unaryOperatorString :: UnaryOperator -> String
212−unaryOperatorString Negate = "-"
213−unaryOperatorString Not = "!"
214−unaryOperatorString BitwiseNot = "~"
216−binaryOperatorString :: BinaryOperator -> String
217−binaryOperatorString Add = "+"
218−binaryOperatorString Subtract = "-"
219−binaryOperatorString Multiply = "*"
220−binaryOperatorString Divide = "/"
221−binaryOperatorString Modulus = "%"
222−binaryOperatorString LessThan = "<"
223−binaryOperatorString LessThanOrEqualTo = "<="
224−binaryOperatorString GreaterThan = ">"
225−binaryOperatorString GreaterThanOrEqualTo = ">="
226−binaryOperatorString BitwiseAnd = "&"
227−binaryOperatorString BitwiseOr = "|"
228−binaryOperatorString BitwiseXor = "^"
229−binaryOperatorString ShiftLeft = "<<"
230−binaryOperatorString ShiftRight = ">>"
231−binaryOperatorString ZeroFillShiftRight = ">>>"
232−binaryOperatorString EqualTo = "==="
233−binaryOperatorString NotEqualTo = "!=="
234−binaryOperatorString And = "&&"
235−binaryOperatorString Or = "||"
236−binaryOperatorString Concat = "+"
238−binderToJs :: String -> String -> Binder -> Gen String
239−binderToJs varName done (StringBinder str) =
240− return $ "if (" ++ varName ++ " === \"" ++ str ++ "\") {" ++ done ++ " }"
241−binderToJs varName done (NumberBinder num) =
242− return $ "if (" ++ varName ++ " === \"" ++ either show show num ++ "\") {" ++ done ++ " }"
243−binderToJs varName done (BooleanBinder True) =
244− return $ "if (" ++ varName ++ ") {" ++ done ++ " }"
245−binderToJs varName done (BooleanBinder False) =
246− return $ "if (!" ++ varName ++ ") {" ++ done ++ " }"
247−binderToJs varName done (VarBinder s) =
248− return $ "var " ++ s ++ " = " ++ varName ++ "; " ++ done
249−binderToJs varName done (NullaryBinder ctor) =
250− return $ "if (" ++ varName ++ ".ctor === \"" ++ ctor ++ "\") { " ++ done ++ " }"
251−binderToJs varName done (UnaryBinder ctor b) = do
253− js <- binderToJs value done b
254− return $ "if (" ++ varName ++ ".ctor === \"" ++ ctor ++ "\") { " ++ "var " ++ value ++ " = " ++ varName ++ ".value; " ++ js ++ " }"
255−binderToJs varName done (ObjectBinder bs) = go done bs
257− go done [] = return done
258− go done ((prop, binder):bs) = do
261− js <- binderToJs propVar done' binder
262− return $ "var " ++ propVar ++ " = " ++ varName ++ "." ++ prop ++ ";" ++ js
263−binderToJs done varName (ArrayBinder bs rest) = do
264− js <- go done rest 0 bs
265− return $ "if (" ++ varName ++ ".length " ++ cmp ++ " " ++ show (length bs) ++ ") { " ++ js ++ " }"
267− cmp = maybe "===" (const ">=") rest
268− go done Nothing _ [] = return done
269− go done (Just binder) index [] = do
271− js <- binderToJs restVar done binder
272− return $ "var " ++ restVar ++ " = " ++ varName ++ ".slice(" ++ show index ++ "); " ++ js
273− go done rest index (binder:bs) = do
275− done' <- go done rest (index + 1) bs
276− js <- binderToJs elVar done' binder
277− return $ "var " ++ elVar ++ " = " ++ varName ++ "[" ++ show index ++ "]; " ++ js
279−objectPropertyToJs :: (String, Value) -> String
280−objectPropertyToJs (key, value) = key ++ ":" ++ valueToJs value
282−statementToJs :: Statement -> String
283−statementToJs (VariableIntroduction name value) = "var " ++ name ++ " = " ++ valueToJs value
284−statementToJs (Assignment target value) = assignmentTargetToJs target ++ " = " ++ valueToJs value
285−statementToJs (While cond sts) = "while ("
286− ++ valueToJs cond ++ ") {"
287− ++ intercalate ";" (map statementToJs sts) ++ "}"
288−statementToJs (For (init, cond, done) sts) = "for (" ++
290− ++ "; " ++ valueToJs cond
291− ++ "; " ++ statementToJs done
292− ++ ") {" ++ intercalate ";" (map statementToJs sts) ++ "}"
293−statementToJs (IfThenElse cond thens elses) = "if ("
294− ++ valueToJs cond ++ ") {"
295− ++ intercalate ";" (map statementToJs thens) ++ "}"
296− ++ flip (maybe "") elses (\sts ->
297− " else {" ++ intercalate ";" (map statementToJs sts) ++ "}")
298−statementToJs (Return value) = "return " ++ valueToJs value
300−assignmentTargetToJs :: AssignmentTarget -> String
301−assignmentTargetToJs (AssignVariable var) = var
302−assignmentTargetToJs (AssignArrayIndex index tgt) = assignmentTargetToJs tgt ++ "[" ++ valueToJs index ++ "]"
303−assignmentTargetToJs (AssignObjectProperty prop tgt) = assignmentTargetToJs tgt ++ "." ++ prop
307−typeLiterals :: Pattern Type String
308−typeLiterals = Pattern $ A.Kleisli match
310− match Number = Just "Number"
311− match String = Just "String"
312− match Boolean = Just "Boolean"
313− match (Array ty) = Just $ "[" ++ typeToPs ty ++ "]"
314− match (Object row) = Just $ "{ " ++ rowToPs row ++ " }"
315− match (TypeVar var) = Just var
316− match (TypeConstructor ctor) = Just ctor
319−rowToPs :: Row -> String
320−rowToPs = (\(tys, tail) -> intercalate "; " (map (uncurry nameAndTypeToPs) tys) ++ tailToPs tail) . toList
322− nameAndTypeToPs :: String -> Type -> String
323− nameAndTypeToPs name ty = name ++ " :: " ++ typeToPs ty
324− tailToPs :: Row -> String
325− tailToPs REmpty = ""
326− tailToPs (RowVar var) = " | " ++ var
327− toList :: Row -> ([(String, Type)], Row)
328− toList (RCons name ty row) = let (tys, rest) = toList row
329− in ((name, ty):tys, rest)
332−typeApp :: Pattern Type (Type, Type)
333−typeApp = Pattern $ A.Kleisli match
335− match (TypeApp f x) = Just (f, x)
338−function :: Pattern Type ([Type], Type)
339−function = Pattern $ A.Kleisli match
341− match (Function args ret) = Just (args, ret)
344−typeToPs :: Type -> String
345−typeToPs = fromMaybe (error "Incomplete pattern") . pattern matchType
347− matchType :: Pattern Type String
348− matchType = buildPrettyPrinter operators (typeLiterals <|> fmap parens matchType)
349− operators :: OperatorTable Type String
351− OperatorTable $ [ AssocL typeApp $ \f x -> f ++ " " ++ x
352− , Split function $ \args ret -> "(" ++ intercalate ", " (map typeToPs args) ++ ") -> " ++ typeToPs ret ]
354−externToJs :: (String, Type) -> String
355−externToJs (name, ty) = "extern " ++ name ++ " :: " ++ typeToPs ty