1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Generate.JavaScript.Builder
6 , Expr(..), Id(..), Prop(..), LValue(..)
7 , Stmt(..), Case(..), VarDecl(..)
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
20import Data.Monoid ((<>))
21import Data.Text (Text)
22import qualified Data.Text.Encoding as Text
36 | Object [(Prop, Expr)]
38 | DotRef Expr Id -- ^ @foo.bar@, spec 11.2.1
39 | BracketRef 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 Id) [Id] [Stmt]
68 = Block [Stmt] -- {stmts}
70 | ExprStmt Expr -- expr;
71 | IfStmt Expr Stmt Stmt -- if (e) stmt1 else stmt2
72 | IfSingleStmt Expr Stmt -- if (e) stmt
73 | Switch Expr [Case] -- switch (e) clauses
74 | While Expr Stmt -- while (e) do stmt
75 | DoWhile Stmt Expr -- do stmt while (e);
76 | Break (Maybe Id) -- break lab;
77 | Continue (Maybe Id) -- continue lab;
78 | Labelled Id Stmt -- lab: stmt
79 | Return (Maybe Expr) -- return expr;
80 | VarDeclStmt [VarDecl] -- var x, y=42;
81 | FunctionStmt Id [Id] [Stmt] -- function f(x, y, z) {...}
89data VarDecl = VarDecl Id (Maybe Expr)
102 | OpInstanceof -- instanceof
106 | OpStrictNEq -- !===
127 | PrefixTypeof -- typeof
134stmtToBuilder :: Stmt -> Builder
139exprToBuilder :: Expr -> Builder
141 snd $ fromExpr "" Whatever expr
148deeper :: Builder -> Builder
153commaSep :: [Builder] -> Builder
155 mconcat (List.intersperse ", " builders)
158commaNewlineSep :: Builder -> [Builder] -> Builder
159commaNewlineSep indent builders =
160 mconcat (List.intersperse (",\n" <> deeper indent) builders)
167fromStmtBlock :: Builder -> [Stmt] -> Builder
168fromStmtBlock indent stmts =
169 mconcat (map (fromStmt indent) stmts)
172fromStmt :: Builder -> Stmt -> Builder
173fromStmt indent statement =
176 fromStmtBlock indent stmts
182 indent <> snd (fromExpr indent Whatever expr) <> ";\n"
184 IfStmt condition thenStmt elseStmt ->
186 [ indent, "if (", snd (fromExpr indent Whatever condition), ") {\n"
187 , fromStmt (deeper indent) thenStmt
188 , indent, "} else {\n"
189 , fromStmt (deeper indent) elseStmt
193 IfSingleStmt condition thenStmt ->
195 [ indent, "if (", snd (fromExpr indent Whatever condition), ") {\n"
196 , fromStmt (deeper indent) thenStmt
200 Switch expr clauses ->
202 [ indent, "switch (", snd (fromExpr indent Whatever expr), ") {\n"
203 , mconcat (map (fromClause (deeper indent)) clauses)
209 [ indent, "while (", snd (fromExpr indent Whatever expr), ") {\n"
210 , fromStmt (deeper indent) stmt
217 , fromStmt (deeper indent) stmt
218 , indent, "} while(", snd (fromExpr indent Whatever expr), ");\n"
224 Break (Just label) ->
225 indent <> "break " <> fromId label <> ";\n"
228 indent <> "continue;\n"
230 Continue (Just label) ->
231 indent <> "continue " <> fromId label <> ";\n"
233 Labelled label stmt ->
235 [ indent, fromId label, ":\n"
236 , fromStmt indent stmt
240 indent <> "return;\n"
242 Return (Just expr) ->
243 indent <> "return " <> snd (fromExpr indent Whatever expr) <> ";\n"
249 indent <> "var " <> commaNewlineSep indent (map (fromVarDecl indent) decls) <> ";\n"
251 FunctionStmt name args stmts ->
252 indent <> "function " <> fromId name <> "(" <> commaSep (map fromId args) <> ") {\n"
254 fromStmtBlock (deeper indent) stmts
263fromClause :: Builder -> Case -> Builder
264fromClause indent clause =
267 indent <> "case " <> snd (fromExpr indent Whatever expr) <> ":\n"
268 <> fromStmtBlock (deeper indent) stmts
271 indent <> "default:\n"
272 <> fromStmtBlock (deeper indent) stmts
279fromId :: Id -> Builder
281 Text.encodeUtf8Builder name
288fromVarDecl :: Builder -> VarDecl -> Builder
289fromVarDecl indent (VarDecl (Id name) maybeExpr) =
292 Text.encodeUtf8Builder name
295 Text.encodeUtf8Builder name <> " = " <> snd (fromExpr indent Whatever expr)
302data Lines = One | Many deriving (Eq)
305merge :: Lines -> Lines -> Lines
307 if a == Many || b == Many then Many else One
310linesMap :: (a -> (Lines, b)) -> [a] -> (Bool, [b])
316 ( any ((==) Many . fst) pairs
321data Grouping = Atomic | Whatever
324parensFor :: Grouping -> Builder -> Builder
325parensFor grouping builder =
328 "(" <> builder <> ")"
334fromExpr :: Builder -> Grouping -> Expr -> (Lines, Builder)
335fromExpr indent grouping expression =
347 (One, if bool then "true" else "false")
355 (anyMany, builders) =
356 linesMap (fromExpr indent Whatever) exprs
361 <> commaNewlineSep indent builders
362 <> "\n" <> indent <> "]"
365 "[" <> commaSep builders <> "]"
373 (anyMany, builders) =
374 linesMap (fromField deeperIndent) fields
379 <> commaNewlineSep indent builders
380 <> "\n" <> indent <> "}"
383 "{" <> commaSep builders <> "}"
388 DotRef expr (Id name) ->
389 makeDot indent expr name
391 BracketRef expr bracketedExpr ->
392 makeBracketed indent expr bracketedExpr
397 fromExpr indent Atomic expr
400 , parensFor grouping (fromPrefix op <> builder)
403 Infix op leftExpr rightExpr ->
406 fromExpr indent Atomic leftExpr
408 (rightLines, right) =
409 fromExpr indent Atomic rightExpr
411 ( merge leftLines rightLines
412 , parensFor grouping (left <> fromInfix op <> right)
415 If condExpr thenExpr elseExpr ->
417 condB = snd (fromExpr indent Atomic condExpr)
418 thenB = snd (fromExpr indent Atomic thenExpr)
419 elseB = snd (fromExpr indent Atomic elseExpr)
422 , parensFor grouping (condB <> " ? " <> thenB <> " : " <> elseB)
425 Assign lValue expr ->
428 fromLValue indent lValue
430 (rightLines, right) =
431 fromExpr indent Whatever expr
433 ( merge leftLines rightLines
434 , parensFor grouping (left <> " = " <> right)
437 Call function args ->
444 snd (fromExpr indent Atomic function)
447 linesMap (fromExpr deeperIndent Whatever) args
450 funcB <> "(\n" <> deeperIndent <> commaNewlineSep indent argsB <> ")"
453 funcB <> "(" <> commaSep argsB <> ")"
455 Function maybeName args stmts ->
457 "function " <> maybe mempty fromId maybeName <> "(" <> commaSep (map fromId args) <> ") {\n"
459 fromStmtBlock (deeper indent) stmts
468fromField :: Builder -> (Prop, Expr) -> (Lines, Builder)
469fromField indent (prop, expr) =
472 fromExpr indent Whatever expr
475 , fromProp prop <> ": " <> builder
479fromProp :: Prop -> Builder
496quoted :: Text -> Builder
498 "'" <> Text.encodeUtf8Builder str <> "'"
505fromLValue :: Builder -> LValue -> (Lines, Builder)
506fromLValue indent lValue =
509 (One, Text.encodeUtf8Builder name)
512 makeDot indent expr field
514 LBracket expr bracketedExpr ->
515 makeBracketed indent expr bracketedExpr
518makeDot :: Builder -> Expr -> Text -> (Lines, Builder)
519makeDot indent expr field =
522 fromExpr indent Atomic expr
524 (lines, builder <> "." <> Text.encodeUtf8Builder field)
527makeBracketed :: Builder -> Expr -> Expr -> (Lines, Builder)
528makeBracketed indent expr bracketedExpr =
531 fromExpr indent Atomic expr
533 (bracketedLines, bracketedBuilder) =
534 fromExpr indent Whatever bracketedExpr
536 ( merge lines bracketedLines
537 , builder <> "[" <> bracketedBuilder <> "]"
545fromPrefix :: PrefixOp -> Builder
552 PrefixTypeof -> "typeof "
555fromInfix :: InfixOp -> Builder
563 OpInstanceof -> " instanceof "
566 OpStrictEq -> " === "
567 OpStrictNEq -> " !=== "
576 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