@@ -1,4 +1,6 @@
1+{-# LANGUAGE PatternGuards #-}
1−module IRTS.CodegenJavaScript (codegenJavaScript ) where
3+module IRTS.CodegenJavaScript (codegenJavaScript) where
3import Idris.AbsSyntax
5import Idris.AbsSyntax
4import IRTS.Bytecode
6import IRTS.Bytecode
@@ -9,51 +11,316 @@ import Core.TT
9import Paths_idris
11import Paths_idris
10import Util.System
12import Util.System
12import Data.Char
15import Data.Char
13import Data.List
16import Data.List
14import System.IO
17import System.IO
19+type NamespaceName = String
21+idrNamespace :: NamespaceName
22+idrNamespace = "__IDR__"
16codegenJavaScript
24codegenJavaScript
17 :: [(Name, SDecl)]
25 :: [(Name, SDecl)]
18 -> FilePath
26 -> FilePath
19 -> OutputType
27 -> OutputType
21codegenJavaScript definitions filename outputType = do
29codegenJavaScript definitions filename outputType = do
22− let body = concat $ map (translateDeclaration . snd) definitions
30+ let def = map (first translateNamespace) definitions
23− output = concat [header, body, footer]
31+ let output = idrRuntime ++ concatMap (translateModule Nothing) def ++ "\nMain.main()"
24 writeFile filename output
32 writeFile filename output
36+ createModule Nothing idrNamespace $ concat
37+ [ "__IDR__.IntType = { type: 'IntType' };"
38+ , "__IDR__.Con = function(i,name,vars)"
39+ , "{this.i = i;this.name = name;this.vars = vars;};"
42+createModule :: Maybe String -> NamespaceName -> String -> String
43+createModule toplevel modname body =
44+ concat [header modname, body, footer modname]
46+ header :: NamespaceName -> String
49+ [ "\nvar " ++ modname ++ ";"
50+ , "(function(" ++ modname ++ "){"
27−header :: String
53+ footer :: NamespaceName -> String
28−header =
54+ footer modname =
29− concat $ map (\line -> line ++ "\n")
55+ let m = maybe "" (++ ".") toplevel ++ modname in
30− ["define(function(require) {",
56+ "\n})("
31− "var m = {};"]
59+ ++ m
63+translateModule :: Maybe String -> ([String], SDecl) -> String
64+translateModule toplevel ([modname], decl) =
65+ let body = translateDeclaration modname decl in
66+ createModule toplevel modname body
67+translateModule toplevel (n:ns, decl) =
68+ createModule toplevel n $ translateModule (Just n) (ns, decl)
34−footer :: String
70+translateIdentifier :: String -> String
35−footer =
71+translateIdentifier =
36− concat $ map (\line -> line ++ "\n")
72+ concatMap replaceBadChars
37− ["return m;",
73+ where replaceBadChars :: Char -> String
38− "});"]
74+ replaceBadChars ' ' = "_"
75+ replaceBadChars '@' = "__at__"
76+ replaceBadChars '[' = "__OSB__"
77+ replaceBadChars ']' = "__CSB__"
78+ replaceBadChars '{' = "__OB__"
79+ replaceBadChars '}' = "__CB__"
80+ replaceBadChars '!' = "__bang__"
81+ replaceBadChars '#' = "__hash__"
82+ replaceBadChars '.' = "__dot__"
83+ replaceBadChars ':' = "__colon__"
84+ replaceBadChars '+' = "__plus__"
85+ replaceBadChars '-' = "__minus__"
86+ replaceBadChars '<' = "__lt__"
87+ replaceBadChars '>' = "__gt__"
88+ replaceBadChars '=' = "__eq__"
89+ replaceBadChars '|' = "__pipe__"
90+ replaceBadChars '\'' = "__apo__"
92+ | isDigit c = "__" ++ [c] ++ "__"
95+translateNamespace :: Name -> [String]
96+translateNamespace (UN _) = [idrNamespace]
97+translateNamespace (NS _ ns) = map translateIdentifier ns
98+translateNamespace (MN _ _) = [idrNamespace]
41translateName :: Name -> String
100translateName :: Name -> String
42−translateName = show
101+translateName (UN name) = translateIdentifier name
102+translateName (NS name _) = translateName name
103+translateName (MN i name) = translateIdentifier name ++ show i
105+translateQualifiedName :: Name -> String
106+translateQualifiedName name =
107+ intercalate "." (translateNamespace name) ++ "." ++ translateName name
109+translateConstant :: Const -> String
110+translateConstant (I i) = show i
111+translateConstant (BI i) = show i
112+translateConstant (Fl f) = show f
113+translateConstant (Ch c) = show c
114+translateConstant (Str s) = show s
115+translateConstant IType = "__IDR__.IntType"
116+translateConstant c =
117+ "(function(){throw 'Unimplemented Const: " ++ show c ++ "';})()"
119+translateParameterlist =
120+ map (\(MN i name) -> name ++ show i)
122+translateDeclaration :: NamespaceName -> SDecl -> String
123+translateDeclaration modname (SFun name params stackSize body) =
126+ ++ translateName name
128+ ++ intercalate "," p
130+ ++ concatMap assignVar (zip [0..] p)
131+ ++ concatMap allocVar [numP..(numP+stackSize-1)]
133+ ++ translateExpression modname body
137+ numP = length params
139+ allocVar :: Int -> String
140+ allocVar n = "var __var_" ++ show n ++ ";\n"
142+ assignVar :: (Int, String) -> String
143+ assignVar (n, s) = "var __var_" ++ show n ++ " = " ++ s ++ ";\n"
146+ p = translateParameterlist params
148+translateVariableName :: LVar -> String
149+translateVariableName (Loc i) =
152+translateExpression :: NamespaceName -> SExp -> String
153+translateExpression modname (SLet name value body) =
155+ ++ translateVariableName name
157+ ++ translateExpression modname body
159+ ++ translateExpression modname value
162+translateExpression _ (SConst cst) =
163+ translateConstant cst
165+translateExpression _ (SV var) =
166+ translateVariableName var
168+translateExpression modname (SApp tc name vars) =
169+ concat (intersperse "." $ translateNamespace name)
171+ ++ translateName name
173+ ++ intercalate "," (map translateVariableName vars)
176+translateExpression _ (SOp op vars)
178+ , (lhs:rhs:_) <- vars = translateBinaryOp "+" lhs rhs
180+ , (lhs:rhs:_) <- vars = translateBinaryOp "-" lhs rhs
182+ , (lhs:rhs:_) <- vars = translateBinaryOp "*" lhs rhs
184+ , (lhs:rhs:_) <- vars = translateBinaryOp "/" lhs rhs
186+ , (lhs:rhs:_) <- vars = translateBinaryOp "%" lhs rhs
188+ , (lhs:rhs:_) <- vars = translateBinaryOp "===" lhs rhs
190+ , (lhs:rhs:_) <- vars = translateBinaryOp "<" lhs rhs
192+ , (lhs:rhs:_) <- vars = translateBinaryOp "<=" lhs rhs
194+ , (lhs:rhs:_) <- vars = translateBinaryOp ">" lhs rhs
196+ , (lhs:rhs:_) <- vars = translateBinaryOp ">=" lhs rhs
199+ , (lhs:rhs:_) <- vars = translateBinaryOp "+" lhs rhs
201+ , (lhs:rhs:_) <- vars = translateBinaryOp "-" lhs rhs
203+ , (lhs:rhs:_) <- vars = translateBinaryOp "*" lhs rhs
205+ , (lhs:rhs:_) <- vars = translateBinaryOp "/" lhs rhs
207+ , (lhs:rhs:_) <- vars = translateBinaryOp "===" lhs rhs
209+ , (lhs:rhs:_) <- vars = translateBinaryOp "<" lhs rhs
211+ , (lhs:rhs:_) <- vars = translateBinaryOp "<=" lhs rhs
213+ , (lhs:rhs:_) <- vars = translateBinaryOp ">" lhs rhs
215+ , (lhs:rhs:_) <- vars = translateBinaryOp ">=" lhs rhs
218+ , (lhs:rhs:_) <- vars = translateBinaryOp "+" lhs rhs
220+ , (lhs:rhs:_) <- vars = translateBinaryOp "-" lhs rhs
222+ , (lhs:rhs:_) <- vars = translateBinaryOp "*" lhs rhs
224+ , (lhs:rhs:_) <- vars = translateBinaryOp "/" lhs rhs
226+ , (lhs:rhs:_) <- vars = translateBinaryOp "%" lhs rhs
228+ , (lhs:rhs:_) <- vars = translateBinaryOp "===" lhs rhs
230+ , (lhs:rhs:_) <- vars = translateBinaryOp "<" lhs rhs
232+ , (lhs:rhs:_) <- vars = translateBinaryOp "<=" lhs rhs
234+ , (lhs:rhs:_) <- vars = translateBinaryOp ">" lhs rhs
236+ , (lhs:rhs:_) <- vars = translateBinaryOp ">=" lhs rhs
239+ , (lhs:rhs:_) <- vars = translateBinaryOp "+" lhs rhs
242+ , (arg:_) <- vars = "String(" ++ translateVariableName arg ++ ");"
245+ translateBinaryOp :: String -> LVar -> LVar -> String
246+ translateBinaryOp f lhs rhs =
247+ translateVariableName lhs
249+ ++ translateVariableName rhs
251+translateExpression _ (SError msg) =
252+ "(function(){throw \'" ++ msg ++ "\';})();"
254+translateExpression _ (SForeign _ _ "putStr" [(FString, var)]) =
255+ "console.log(" ++ translateVariableName var ++ ");"
257+translateExpression _ (SForeign _ _ fun args) =
260+ ++ intercalate "," (map (translateVariableName . snd) args)
263+translateExpression modname (SChkCase var cases) =
265+ ++ intercalate " else " (map (translateCase modname "e") cases)
267+ ++ translateVariableName var
270+translateExpression modname (SCase var cases) =
272+ ++ intercalate " else " (map (translateCase modname "e") cases)
274+ ++ translateVariableName var
277+translateExpression _ (SCon i name vars) =
278+ concat [ "new __IDR__.Con("
281+ , '\'' : translateQualifiedName name ++ "\',["
282+ , intercalate "," $ map translateVariableName vars
286+translateExpression modname (SUpdate var e) =
287+ "(function(){\nreturn ("
288+ ++ translateVariableName var
289+ ++ " = " ++ translateExpression modname e
292+translateExpression modname (SProj var i) =
293+ "(function(){\nreturn "
294+ ++ translateVariableName var ++ ".vars[" ++ show i ++"];\n})()"
296+translateExpression _ SNothing = "null"
298+translateExpression _ e =
299+ "(function(){throw 'Not yet implemented: "
300+ ++ filter (/= '\'') (show e)
303+translateCase :: String -> String -> SAlt -> String
304+translateCase modname _ (SDefaultCase e) =
305+ createIfBlock "true" (translateExpression modname e)
45−translateDeclaration :: SDecl -> String
307+translateCase modname var (SConstCase cst e) =
46−translateDeclaration (SFun name parameterNames stackSize body) =
308+ let cond = var ++ " === " ++ translateConstant cst in
47− concat ["m[\"", translateName name, "\"] = function(s) { ",
48− translateExpression body, " ",
309+ createIfBlock cond (translateExpression modname e)
49− intercalate " " $ take (length parameterNames) $ repeat "s.pop();",
311+translateCase modname var (SConCase a i name vars e) =
312+ let isCon = var ++ " instanceof __IDR__.Con"
313+ isI = show i ++ " === " ++ var ++ ".i"
314+ params = intercalate "," $ map (("__var_" ++) . show) [a..(a+length vars)]
315+ args = ".apply(this," ++ var ++ ".vars)"
319+ ++ "){\nreturn " ++ b ++ "\n})" ++ args
320+ cond = intercalate " && " [isCon, isI] in
321+ createIfBlock cond $ f (translateExpression modname e)
53−translateExpression :: SExp -> String
323+createIfBlock cond e =
54−translateExpression (SLet name value body) =
324+ "if (" ++ cond ++") {\n"
55− intercalate " "
325+ ++ "return " ++ e
56− $ [translateExpression value,
326+ ++ ";\n}"
57− translateExpression body,
58− "s.pop();", "s.pop();"]
59−translateExpression _ = "..."