@@ -1,22 +1,155 @@
1{-# OPTIONS_GHC -Wall #-}
1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3−module Generate.JavaScript.Builder (stmtsToText) where
3+module Generate.JavaScript.Builder
4+ ( Expr(..), Id(..), Prop(..), LValue(..)
5+ , Stmt(..), Case(..), VarDecl(..)
6+ , InfixOp(..), AssignOp(..), PrefixOp(..)
11+-- Based on the language-ecmascript package.
12+-- https://hackage.haskell.org/package/language-ecmascript
13+-- They did the hard work of reading the spec to figure out
14+-- how all the types should fit together.
16+import Prelude hiding (lines)
5import qualified Data.List as List
17import qualified Data.List as List
6import Data.Monoid ((<>))
18import Data.Monoid ((<>))
7−import qualified Data.Text.Lazy as LazyText
19+import Data.Text (Text)
8import Data.Text.Lazy.Builder
20import Data.Text.Lazy.Builder
9import Data.Text.Lazy.Builder.Int (decimal)
21import Data.Text.Lazy.Builder.Int (decimal)
10import Data.Text.Lazy.Builder.RealFloat (realFloat)
22import Data.Text.Lazy.Builder.RealFloat (realFloat)
11−import Language.ECMAScript3.Syntax
23+import qualified Data.Text.Lazy as LazyText
12−import Prelude hiding (lines)
24+
37+ | Object [(Prop, Expr)]
39+ | DotRef Expr Id -- ^ @foo.bar@, spec 11.2.1
40+ | BracketRef Expr Expr -- ^ @foo[bar]@, spec 11.2.1
41+ | Prefix PrefixOp Expr
42+ | Infix InfixOp Expr Expr
44+ | Assign AssignOp LValue Expr
45+ | Call Expr [Expr] -- ^ @f(x,y,z)@, spec 11.2.3
46+ | Function (Maybe Id) [Id] [Stmt]
69+ = Block [Stmt] -- {stmts}
71+ | ExprStmt Expr -- expr;
72+ | IfStmt Expr Stmt Stmt -- if (e) stmt1 else stmt2
73+ | IfSingleStmt Expr Stmt -- if (e) stmt
74+ | Switch Expr [Case] -- switch (e) clauses
75+ | While Expr Stmt -- while (e) do stmt
76+ | DoWhile Stmt Expr -- do stmt while (e);
77+ | Break (Maybe Id) -- break lab;
78+ | Continue (Maybe Id) -- continue lab;
79+ | Labelled Id Stmt -- lab: stmt
80+ | Return (Maybe Expr) -- return expr;
81+ | VarDeclStmt [VarDecl] -- var x, y=42;
82+ | FunctionStmt Id [Id] [Stmt] -- function f(x, y, z) {...}
90+data VarDecl = VarDecl Id (Maybe Expr)
103+ | OpInstanceof -- instanceof
107+ | OpStrictNEq -- !===
130+ | OpAssignLShift -- <<=
131+ | OpAssignSpRShift -- >>=
132+ | OpAssignZfRShift -- >>>=
133+ | OpAssignBAnd -- &=
134+ | OpAssignBXor -- ^=
143+ | PrefixTypeof -- typeof
144+ | PrefixVoid -- void
145+ | PrefixDelete -- delete
16-- CONVERT TO LAZY TEXT
149-- CONVERT TO LAZY TEXT
19−stmtsToText :: [Statement a] -> LazyText.Text
152+stmtsToText :: [Stmt] -> LazyText.Text
20stmtsToText stmts =
153stmtsToText stmts =
21 toLazyText (fromStmtBlock "" stmts)
154 toLazyText (fromStmtBlock "" stmts)
@@ -44,24 +177,24 @@ commaNewlineSep indent builders =
44-- STATEMENTS
177-- STATEMENTS
47−fromStmtBlock :: Builder -> [Statement a] -> Builder
180+fromStmtBlock :: Builder -> [Stmt] -> Builder
48fromStmtBlock indent stmts =
181fromStmtBlock indent stmts =
49 mconcat (map (fromStmt indent) stmts)
182 mconcat (map (fromStmt indent) stmts)
52−fromStmt :: Builder -> Statement a -> Builder
185+fromStmt :: Builder -> Stmt -> Builder
53fromStmt indent statement =
186fromStmt indent statement =
54 case statement of
187 case statement of
55− BlockStmt _ stmts ->
188+ Block stmts ->
56 fromStmtBlock indent stmts
189 fromStmtBlock indent stmts
58− EmptyStmt _ ->
191+ EmptyStmt ->
61− ExprStmt _ expr ->
194+ ExprStmt expr ->
62 indent <> snd (fromExpr indent Whatever expr) <> ";\n"
195 indent <> snd (fromExpr indent Whatever expr) <> ";\n"
64− IfStmt _ condition thenStmt elseStmt ->
197+ IfStmt condition thenStmt elseStmt ->
66 [ indent, "if (", snd (fromExpr indent Whatever condition), ") {\n"
199 [ indent, "if (", snd (fromExpr indent Whatever condition), ") {\n"
67 , fromStmt (deeper indent) thenStmt
200 , fromStmt (deeper indent) thenStmt
@@ -70,80 +203,65 @@ fromStmt indent statement =
70 , indent, "}\n"
203 , indent, "}\n"
73− IfSingleStmt _ condition thenStmt ->
206+ IfSingleStmt condition thenStmt ->
75 [ indent, "if (", snd (fromExpr indent Whatever condition), ") {\n"
208 [ indent, "if (", snd (fromExpr indent Whatever condition), ") {\n"
76 , fromStmt (deeper indent) thenStmt
209 , fromStmt (deeper indent) thenStmt
77 , indent, "}\n"
210 , indent, "}\n"
80− SwitchStmt _ expr clauses ->
213+ Switch expr clauses ->
82 [ indent, "switch (", snd (fromExpr indent Whatever expr), ") {\n"
215 [ indent, "switch (", snd (fromExpr indent Whatever expr), ") {\n"
83 , mconcat (map (fromClause (deeper indent)) clauses)
216 , mconcat (map (fromClause (deeper indent)) clauses)
84 , indent, "}\n"
217 , indent, "}\n"
87− WhileStmt _ expr stmt ->
220+ While expr stmt ->
89 [ indent, "while (", snd (fromExpr indent Whatever expr), ") {\n"
222 [ indent, "while (", snd (fromExpr indent Whatever expr), ") {\n"
90 , fromStmt (deeper indent) stmt
223 , fromStmt (deeper indent) stmt
91 , indent, "}\n"
224 , indent, "}\n"
94− DoWhileStmt _ stmt expr ->
227+ DoWhile stmt expr ->
96 [ indent, "do {\n"
229 [ indent, "do {\n"
97 , fromStmt (deeper indent) stmt
230 , fromStmt (deeper indent) stmt
98 , indent, "} while(", snd (fromExpr indent Whatever expr), ");\n"
231 , indent, "} while(", snd (fromExpr indent Whatever expr), ");\n"
101− BreakStmt _ Nothing ->
234+ Break Nothing ->
102 indent <> "break;\n"
235 indent <> "break;\n"
104− BreakStmt _ (Just label) ->
237+ Break (Just label) ->
105 indent <> "break " <> fromId label <> ";\n"
238 indent <> "break " <> fromId label <> ";\n"
107− ContinueStmt _ Nothing ->
240+ Continue Nothing ->
108 indent <> "continue;\n"
241 indent <> "continue;\n"
110− ContinueStmt _ (Just label) ->
243+ Continue (Just label) ->
111 indent <> "continue " <> fromId label <> ";\n"
244 indent <> "continue " <> fromId label <> ";\n"
113− LabelledStmt _ label stmt ->
246+ Labelled label stmt ->
115 [ indent, fromId label, ":\n"
248 [ indent, fromId label, ":\n"
116 , fromStmt indent stmt
249 , fromStmt indent stmt
119− ForInStmt _ _ _ _ ->
122− ForStmt _ _ _ _ _ ->
129− indent <> "throw " <> snd (fromExpr indent Whatever expr) <> ";\n"
131− ReturnStmt _ Nothing ->
252+ Return Nothing ->
132 indent <> "return;\n"
253 indent <> "return;\n"
134− ReturnStmt _ (Just expr) ->
255+ Return (Just expr) ->
135 indent <> "return " <> snd (fromExpr indent Whatever expr) <> ";\n"
256 indent <> "return " <> snd (fromExpr indent Whatever expr) <> ";\n"
140− VarDeclStmt _ [] ->
258+ VarDeclStmt [] ->
143− VarDeclStmt _ decls ->
261+ VarDeclStmt decls ->
144 indent <> "var " <> commaNewlineSep indent (map (fromVarDecl indent) decls) <> ";\n"
262 indent <> "var " <> commaNewlineSep indent (map (fromVarDecl indent) decls) <> ";\n"
146− FunctionStmt _ name args stmts ->
264+ FunctionStmt name args stmts ->
147 indent <> "function " <> fromId name <> "(" <> commaSep (map fromId args) <> ") {\n"
265 indent <> "function " <> fromId name <> "(" <> commaSep (map fromId args) <> ") {\n"
149 fromStmtBlock (deeper indent) stmts
267 fromStmtBlock (deeper indent) stmts
@@ -155,14 +273,14 @@ fromStmt indent statement =
155-- SWITCH CLAUSES
273-- SWITCH CLAUSES
158−fromClause :: Builder -> CaseClause a -> Builder
276+fromClause :: Builder -> Case -> Builder
159fromClause indent clause =
277fromClause indent clause =
160 case clause of
278 case clause of
161− CaseClause _ expr stmts ->
279+ Case expr stmts ->
162 indent <> "case " <> snd (fromExpr indent Whatever expr) <> ":\n"
280 indent <> "case " <> snd (fromExpr indent Whatever expr) <> ":\n"
163 <> fromStmtBlock (deeper indent) stmts
281 <> fromStmtBlock (deeper indent) stmts
165− CaseDefault _ stmts ->
283+ Default stmts ->
166 indent <> "default:\n"
284 indent <> "default:\n"
167 <> fromStmtBlock (deeper indent) stmts
285 <> fromStmtBlock (deeper indent) stmts
@@ -171,23 +289,23 @@ fromClause indent clause =
174−fromId :: Id a -> Builder
292+fromId :: Id -> Builder
175−fromId (Id _ name) =
293+fromId (Id name) =
176− fromString name
294+ fromText name
180-- VAR DECLS
298-- VAR DECLS
183−fromVarDecl :: Builder -> VarDecl a -> Builder
301+fromVarDecl :: Builder -> VarDecl -> Builder
184−fromVarDecl indent (VarDecl _ (Id _ name) maybeExpr) =
302+fromVarDecl indent (VarDecl (Id name) maybeExpr) =
185 case maybeExpr of
303 case maybeExpr of
186 Nothing ->
304 Nothing ->
187− fromString name
305+ fromText name
189 Just expr ->
307 Just expr ->
190− fromString name <> " = " <> snd (fromExpr indent Whatever expr)
308+ fromText name <> " = " <> snd (fromExpr indent Whatever expr)
@@ -226,31 +344,25 @@ parensFor grouping builder =
229−fromExpr :: Builder -> Grouping -> Expression a -> (Lines, Builder)
347+fromExpr :: Builder -> Grouping -> Expr -> (Lines, Builder)
230fromExpr indent grouping expression =
348fromExpr indent grouping expression =
231 case expression of
349 case expression of
232− StringLit _ string ->
350+ String string ->
233 (One, quoted string)
351 (One, quoted string)
235− RegexpLit _ _ _ _ ->
353+ Float n ->
239 (One, realFloat n)
354 (One, realFloat n)
241− IntLit _ n ->
356+ Int n ->
242 (One, decimal n)
357 (One, decimal n)
244− BoolLit _ True ->
359+ Bool bool ->
245− (One, "true")
360+ (One, if bool then "true" else "false")
250− NullLit _ ->
362+ Null ->
251 (One, "null")
363 (One, "null")
253− ArrayLit _ exprs ->
365+ Array exprs ->
254 (,) Many $
366 (,) Many $
256 (anyMany, builders) =
368 (anyMany, builders) =
@@ -265,7 +377,7 @@ fromExpr indent grouping expression =
266 "[" <> commaSep builders <> "]"
378 "[" <> commaSep builders <> "]"
268− ObjectLit _ fields ->
380+ Object fields ->
269 (,) Many $
381 (,) Many $
271 deeperIndent =
383 deeperIndent =
@@ -283,22 +395,16 @@ fromExpr indent grouping expression =
284 "{" <> commaSep builders <> "}"
396 "{" <> commaSep builders <> "}"
289− VarRef _ name ->
398+ VarRef name ->
290 (One, fromId name)
399 (One, fromId name)
292− DotRef _ expr (Id _ name) ->
401+ DotRef expr (Id name) ->
293 makeDot indent expr name
402 makeDot indent expr name
295− BracketRef _ expr bracketedExpr ->
404+ BracketRef expr bracketedExpr ->
296 makeBracketed indent expr bracketedExpr
405 makeBracketed indent expr bracketedExpr
301− PrefixExpr _ op expr ->
407+ Prefix op expr ->
303 (lines, builder) =
409 (lines, builder) =
304 fromExpr indent Atomic expr
410 fromExpr indent Atomic expr
@@ -307,10 +413,7 @@ fromExpr indent grouping expression =
307 , parensFor grouping (fromPrefix op <> builder)
413 , parensFor grouping (fromPrefix op <> builder)
310− UnaryAssignExpr _ _ _ ->
313− InfixExpr _ op leftExpr rightExpr ->
416+ Infix op leftExpr rightExpr ->
315 (leftLines, left) =
418 (leftLines, left) =
316 fromExpr indent Atomic leftExpr
419 fromExpr indent Atomic leftExpr
@@ -322,7 +425,7 @@ fromExpr indent grouping expression =
322 , parensFor grouping (left <> fromInfix op <> right)
425 , parensFor grouping (left <> fromInfix op <> right)
325− CondExpr _ condExpr thenExpr elseExpr ->
428+ If condExpr thenExpr elseExpr ->
327 condB = snd (fromExpr indent Atomic condExpr)
430 condB = snd (fromExpr indent Atomic condExpr)
328 thenB = snd (fromExpr indent Atomic thenExpr)
431 thenB = snd (fromExpr indent Atomic thenExpr)
@@ -332,7 +435,7 @@ fromExpr indent grouping expression =
332 , parensFor grouping (condB <> " ? " <> thenB <> " : " <> elseB)
435 , parensFor grouping (condB <> " ? " <> thenB <> " : " <> elseB)
335− AssignExpr _ op lValue expr ->
438+ Assign op lValue expr ->
337 (leftLines, left) =
440 (leftLines, left) =
338 fromLValue indent lValue
441 fromLValue indent lValue
@@ -344,10 +447,7 @@ fromExpr indent grouping expression =
344 , parensFor grouping (left <> fromAssign op <> right)
447 , parensFor grouping (left <> fromAssign op <> right)
350− CallExpr _ function args ->
450+ Call function args ->
351 (,) Many $
451 (,) Many $
353 deeperIndent =
453 deeperIndent =
@@ -365,7 +465,7 @@ fromExpr indent grouping expression =
366 funcB <> "(" <> commaSep argsB <> ")"
466 funcB <> "(" <> commaSep argsB <> ")"
368− FuncExpr _ maybeName args stmts ->
468+ Function maybeName args stmts ->
369 (,) Many $
469 (,) Many $
370 "function " <> maybe mempty fromId maybeName <> "(" <> commaSep (map fromId args) <> ") {\n"
470 "function " <> maybe mempty fromId maybeName <> "(" <> commaSep (map fromId args) <> ") {\n"
@@ -378,7 +478,7 @@ fromExpr indent grouping expression =
381−fromField :: Builder -> (Prop a, Expression a) -> (Lines, Builder)
481+fromField :: Builder -> (Prop, Expr) -> (Lines, Builder)
382fromField indent (prop, expr) =
482fromField indent (prop, expr) =
384 (lines, builder) =
484 (lines, builder) =
@@ -389,16 +489,16 @@ fromField indent (prop, expr) =
392−fromProp :: Prop a -> Builder
492+fromProp :: Prop -> Builder
393fromProp prop =
493fromProp prop =
394 case prop of
494 case prop of
395− PropId _ name ->
495+ IdProp name ->
396 fromId name
496 fromId name
398− PropString _ string ->
498+ StringProp string ->
399 quoted string
499 quoted string
401− PropNum _ n ->
501+ IntProp n ->
402 decimal n
502 decimal n
@@ -406,54 +506,38 @@ fromProp prop =
406-- STRINGS
506-- STRINGS
409−quoted :: String -> Builder
509+quoted :: Text -> Builder
410−quoted string =
510+quoted str =
411− fromString ('\'' : foldr escapeCons "'" string)
511+ "'" <> fromText str <> "'"
414−-- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#String_literals
415−escapeCons :: Char -> String -> String
416−escapeCons char rest =
418− '\b' -> '\\' : 'b' : rest
419− '\f' -> '\\' : 'f' : rest
420− '\n' -> '\\' : 'n' : rest
421− '\r' -> '\\' : 'r' : rest
422− '\t' -> '\\' : 't' : rest
423− '\v' -> '\\' : 'v' : rest
424− '\"' -> '\\' : '"' : rest
425− '\'' -> '\\' : '\'' : rest
426− '\\' -> '\\' : '\\' : rest
434−fromLValue :: Builder -> LValue a -> (Lines, Builder)
518+fromLValue :: Builder -> LValue -> (Lines, Builder)
435fromLValue indent lValue =
519fromLValue indent lValue =
436 case lValue of
520 case lValue of
437− LVar _ name ->
521+ LVar name ->
438− (One, fromString name)
522+ (One, fromText name)
440− LDot _ expr field ->
524+ LDot expr field ->
441 makeDot indent expr field
525 makeDot indent expr field
443− LBracket _ expr bracketedExpr ->
527+ LBracket expr bracketedExpr ->
444 makeBracketed indent expr bracketedExpr
528 makeBracketed indent expr bracketedExpr
447−makeDot :: Builder -> Expression a -> String -> (Lines, Builder)
531+makeDot :: Builder -> Expr -> Text -> (Lines, Builder)
448makeDot indent expr field =
532makeDot indent expr field =
450 (lines, builder) =
534 (lines, builder) =
451 fromExpr indent Atomic expr
535 fromExpr indent Atomic expr
453− (lines, builder <> "." <> fromString field)
537+ (lines, builder <> "." <> fromText field)
456−makeBracketed :: Builder -> Expression a -> Expression a -> (Lines, Builder)
540+makeBracketed :: Builder -> Expr -> Expr -> (Lines, Builder)
457makeBracketed indent expr bracketedExpr =
541makeBracketed indent expr bracketedExpr =
459 (lines, builder) =
543 (lines, builder) =