1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Generate.JavaScript.Builder
8 , InfixOp(..), PrefixOp(..)
12-- Based on the language-ecmascript package.
13-- https://hackage.haskell.org/package/language-ecmascript
14-- They did the hard work of reading the spec to figure out
15-- how all the types should fit together.
17import Prelude hiding (lines)
18import qualified Data.List as List
19import Data.ByteString.Builder as B
20import Data.Monoid ((<>))
21import qualified Generate.JavaScript.Name as Name
22import Generate.JavaScript.Name (Name)
36 | Object [(Name, Expr)]
38 | Access Expr Name -- ^ @foo.bar@, spec 11.2.1
39 | Index Expr Expr -- ^ @foo[bar]@, spec 11.2.1
40 | Prefix PrefixOp Expr
41 | Infix InfixOp Expr Expr
44 | Call Expr [Expr] -- ^ @f(x,y,z)@, spec 11.2.3
45 | Function (Maybe Name) [Name] [Stmt]
59 = Block [Stmt] -- {stmts}
61 | ExprStmt Expr -- expr;
62 | IfStmt Expr Stmt Stmt -- if (e) stmt1 else stmt2
63 | Switch Expr [Case] -- switch (e) clauses
64 | While Expr Stmt -- while (e) do stmt
65 | DoWhile Stmt Expr -- do stmt while (e);
66 | Break (Maybe Name) -- break lab;
67 | Continue (Maybe Name) -- continue lab;
68 | Labelled Name Stmt -- lab: stmt
69 | Return (Maybe Expr) -- return expr;
70 | Var [(Name, Maybe Expr)] -- var x, y=42;
71 | FunctionStmt Name [Name] [Stmt] -- function f(x, y, z) {...}
89 | OpInstanceof -- instanceof
114 | PrefixTypeof -- typeof
121stmtToBuilder :: Stmt -> Builder
126exprToBuilder :: Expr -> Builder
128 snd $ fromExpr "" Whatever expr
135deeper :: Builder -> Builder
140commaSep :: [Builder] -> Builder
142 mconcat (List.intersperse ", " builders)
145commaNewlineSep :: Builder -> [Builder] -> Builder
146commaNewlineSep indent builders =
147 mconcat (List.intersperse (",\n" <> deeper indent) builders)
154fromStmtBlock :: Builder -> [Stmt] -> Builder
155fromStmtBlock indent stmts =
156 mconcat (map (fromStmt indent) stmts)
159fromStmt :: Builder -> Stmt -> Builder
160fromStmt indent statement =
163 fromStmtBlock indent stmts
169 indent <> snd (fromExpr indent Whatever expr) <> ";\n"
171 IfStmt condition thenStmt elseStmt ->
173 [ indent, "if (", snd (fromExpr indent Whatever condition), ") {\n"
174 , fromStmt (deeper indent) thenStmt
175 , indent, "} else {\n"
176 , fromStmt (deeper indent) elseStmt
180 Switch expr clauses ->
182 [ indent, "switch (", snd (fromExpr indent Whatever expr), ") {\n"
183 , mconcat (map (fromClause (deeper indent)) clauses)
189 [ indent, "while (", snd (fromExpr indent Whatever expr), ") {\n"
190 , fromStmt (deeper indent) stmt
197 , fromStmt (deeper indent) stmt
198 , indent, "} while(", snd (fromExpr indent Whatever expr), ");\n"
204 Break (Just label) ->
205 indent <> "break " <> Name.toBuilder label <> ";\n"
208 indent <> "continue;\n"
210 Continue (Just label) ->
211 indent <> "continue " <> Name.toBuilder label <> ";\n"
213 Labelled label stmt ->
215 [ indent, Name.toBuilder label, ":\n"
216 , fromStmt indent stmt
220 indent <> "return;\n"
222 Return (Just expr) ->
223 indent <> "return " <> snd (fromExpr indent Whatever expr) <> ";\n"
229 indent <> "var " <> commaNewlineSep indent (map (varToBuilder indent) vars) <> ";\n"
231 FunctionStmt name args stmts ->
232 indent <> "function " <> Name.toBuilder name <> "(" <> commaSep (map Name.toBuilder args) <> ") {\n"
234 fromStmtBlock (deeper indent) stmts
243fromClause :: Builder -> Case -> Builder
244fromClause indent clause =
247 indent <> "case " <> snd (fromExpr indent Whatever expr) <> ":\n"
248 <> fromStmtBlock (deeper indent) stmts
251 indent <> "default:\n"
252 <> fromStmtBlock (deeper indent) stmts
259varToBuilder :: Builder -> (Name, Maybe Expr) -> Builder
260varToBuilder indent (name, maybeExpr) =
266 Name.toBuilder name <> " = " <> snd (fromExpr indent Whatever expr)
273data Lines = One | Many deriving (Eq)
276merge :: Lines -> Lines -> Lines
278 if a == Many || b == Many then Many else One
281linesMap :: (a -> (Lines, b)) -> [a] -> (Bool, [b])
287 ( any ((==) Many . fst) pairs
292data Grouping = Atomic | Whatever
295parensFor :: Grouping -> Builder -> Builder
296parensFor grouping builder =
299 "(" <> builder <> ")"
305fromExpr :: Builder -> Grouping -> Expr -> (Lines, Builder)
306fromExpr indent grouping expression =
309 (One, "'" <> string <> "'")
318 (One, if bool then "true" else "false")
326 (anyMany, builders) =
327 linesMap (fromExpr indent Whatever) exprs
332 <> commaNewlineSep indent builders
333 <> "\n" <> indent <> "]"
336 "[" <> commaSep builders <> "]"
344 (anyMany, builders) =
345 linesMap (fromField deeperIndent) fields
350 <> commaNewlineSep indent builders
351 <> "\n" <> indent <> "}"
354 "{" <> commaSep builders <> "}"
357 (One, Name.toBuilder name)
360 makeDot indent expr field
362 Index expr bracketedExpr ->
363 makeBracketed indent expr bracketedExpr
368 fromExpr indent Atomic expr
371 , parensFor grouping (fromPrefix op <> builder)
374 Infix op leftExpr rightExpr ->
377 fromExpr indent Atomic leftExpr
379 (rightLines, right) =
380 fromExpr indent Atomic rightExpr
382 ( merge leftLines rightLines
383 , parensFor grouping (left <> fromInfix op <> right)
386 If condExpr thenExpr elseExpr ->
388 condB = snd (fromExpr indent Atomic condExpr)
389 thenB = snd (fromExpr indent Atomic thenExpr)
390 elseB = snd (fromExpr indent Atomic elseExpr)
393 , parensFor grouping (condB <> " ? " <> thenB <> " : " <> elseB)
396 Assign lValue expr ->
399 fromLValue indent lValue
401 (rightLines, right) =
402 fromExpr indent Whatever expr
404 ( merge leftLines rightLines
405 , parensFor grouping (left <> " = " <> right)
408 Call function args ->
415 snd (fromExpr indent Atomic function)
418 linesMap (fromExpr deeperIndent Whatever) args
421 funcB <> "(\n" <> deeperIndent <> commaNewlineSep indent argsB <> ")"
424 funcB <> "(" <> commaSep argsB <> ")"
426 Function maybeName args stmts ->
428 "function " <> maybe mempty Name.toBuilder maybeName <> "(" <> commaSep (map Name.toBuilder args) <> ") {\n"
430 fromStmtBlock (deeper indent) stmts
439fromField :: Builder -> (Name, Expr) -> (Lines, Builder)
440fromField indent (field, expr) =
443 fromExpr indent Whatever expr
446 , Name.toBuilder field <> ": " <> builder
454fromLValue :: Builder -> LValue -> (Lines, Builder)
455fromLValue indent lValue =
458 (One, Name.toBuilder name)
461 makeDot indent expr field
463 LBracket expr bracketedExpr ->
464 makeBracketed indent expr bracketedExpr
467makeDot :: Builder -> Expr -> Name -> (Lines, Builder)
468makeDot indent expr field =
471 fromExpr indent Atomic expr
473 (lines, builder <> "." <> Name.toBuilder field)
476makeBracketed :: Builder -> Expr -> Expr -> (Lines, Builder)
477makeBracketed indent expr bracketedExpr =
480 fromExpr indent Atomic expr
482 (bracketedLines, bracketedBuilder) =
483 fromExpr indent Whatever bracketedExpr
485 ( merge lines bracketedLines
486 , builder <> "[" <> bracketedBuilder <> "]"
494fromPrefix :: PrefixOp -> Builder
501 PrefixTypeof -> "typeof "
504fromInfix :: InfixOp -> Builder
512 OpInstanceof -> " instanceof "
515 OpStrictEq -> " === "
516 OpStrictNEq -> " !=== "
525 OpZfRShift -> " >>> "
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list