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)
23import qualified Json.Encode as Json
38 | Object [(Name, Expr)]
40 | Access Expr Name -- foo.bar
41 | Index Expr Expr -- foo[bar]
42 | Prefix PrefixOp Expr
43 | Infix InfixOp Expr Expr
47 | Function (Maybe Name) [Name] [Stmt]
64 | IfStmt Expr Stmt Stmt
68 | Continue (Maybe Name)
75 | FunctionStmt Name [Name] [Stmt]
112 | PrefixComplement -- ~
119stmtToBuilder :: Stmt -> Builder
124exprToBuilder :: Expr -> Builder
126 snd $ fromExpr "" Whatever expr
133deeper :: Builder -> Builder
138commaSep :: [Builder] -> Builder
140 mconcat (List.intersperse ", " builders)
143commaNewlineSep :: Builder -> [Builder] -> Builder
144commaNewlineSep indent builders =
145 mconcat (List.intersperse (",\n" <> deeper indent) builders)
152fromStmtBlock :: Builder -> [Stmt] -> Builder
153fromStmtBlock indent stmts =
154 mconcat (map (fromStmt indent) stmts)
157fromStmt :: Builder -> Stmt -> Builder
158fromStmt indent statement =
161 fromStmtBlock indent stmts
167 indent <> snd (fromExpr indent Whatever expr) <> ";\n"
169 IfStmt condition thenStmt elseStmt ->
171 [ indent, "if (", snd (fromExpr indent Whatever condition), ") {\n"
172 , fromStmt (deeper indent) thenStmt
173 , indent, "} else {\n"
174 , fromStmt (deeper indent) elseStmt
178 Switch expr clauses ->
180 [ indent, "switch (", snd (fromExpr indent Whatever expr), ") {\n"
181 , mconcat (map (fromClause (deeper indent)) clauses)
187 [ indent, "while (", snd (fromExpr indent Whatever expr), ") {\n"
188 , fromStmt (deeper indent) stmt
195 Break (Just label) ->
196 indent <> "break " <> Name.toBuilder label <> ";\n"
199 indent <> "continue;\n"
201 Continue (Just label) ->
202 indent <> "continue " <> Name.toBuilder label <> ";\n"
204 Labelled label stmt ->
206 [ indent, Name.toBuilder label, ":\n"
207 , fromStmt indent stmt
210 Try tryStmt errorName catchStmt ->
213 , fromStmt (deeper indent) tryStmt
214 , indent, "} catch (", Name.toBuilder errorName, ") {\n"
215 , fromStmt (deeper indent) catchStmt
220 "throw " <> snd (fromExpr indent Whatever expr) <> ";"
223 indent <> "return;\n"
225 Return (Just expr) ->
226 indent <> "return " <> snd (fromExpr indent Whatever expr) <> ";\n"
229 indent <> "var " <> Name.toBuilder name <> " = " <> snd (fromExpr indent Whatever expr) <> ";\n"
235 indent <> "var " <> commaNewlineSep indent (map (varToBuilder indent) vars) <> ";\n"
237 FunctionStmt name args stmts ->
238 indent <> "function " <> Name.toBuilder name <> "(" <> commaSep (map Name.toBuilder args) <> ") {\n"
240 fromStmtBlock (deeper indent) stmts
249fromClause :: Builder -> Case -> Builder
250fromClause indent clause =
253 indent <> "case " <> snd (fromExpr indent Whatever expr) <> ":\n"
254 <> fromStmtBlock (deeper indent) stmts
257 indent <> "default:\n"
258 <> fromStmtBlock (deeper indent) stmts
265varToBuilder :: Builder -> (Name, Expr) -> Builder
266varToBuilder indent (name, expr) =
267 Name.toBuilder name <> " = " <> snd (fromExpr indent Whatever expr)
274data Lines = One | Many deriving (Eq)
277merge :: Lines -> Lines -> Lines
279 if a == Many || b == Many then Many else One
282linesMap :: (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")
324 ( One, Json.encodeUgly json )
329 (anyMany, builders) = linesMap (fromExpr indent Whatever) exprs
334 <> commaNewlineSep indent builders
335 <> "\n" <> indent <> "]"
337 "[" <> commaSep builders <> "]"
342 deeperIndent = deeper indent
343 (anyMany, builders) = linesMap (fromField deeperIndent) fields
348 <> commaNewlineSep indent builders
349 <> "\n" <> indent <> "}"
351 "{" <> commaSep builders <> "}"
354 (One, Name.toBuilder name)
357 makeDot indent expr field
359 Index expr bracketedExpr ->
360 makeBracketed indent expr bracketedExpr
364 (lines, builder) = fromExpr indent Atomic expr
367 , parensFor grouping (fromPrefix op <> builder)
370 Infix op leftExpr rightExpr ->
372 (leftLines , left ) = fromExpr indent Atomic leftExpr
373 (rightLines, right) = fromExpr indent Atomic rightExpr
375 ( merge leftLines rightLines
376 , parensFor grouping (left <> fromInfix op <> right)
379 If condExpr thenExpr elseExpr ->
381 condB = snd (fromExpr indent Atomic condExpr)
382 thenB = snd (fromExpr indent Atomic thenExpr)
383 elseB = snd (fromExpr indent Atomic elseExpr)
386 , parensFor grouping (condB <> " ? " <> thenB <> " : " <> elseB)
389 Assign lValue expr ->
391 (leftLines , left ) = fromLValue indent lValue
392 (rightLines, right) = fromExpr indent Whatever expr
394 ( merge leftLines rightLines
395 , parensFor grouping (left <> " = " <> right)
398 Call function args ->
401 deeperIndent = deeper indent
402 funcB = snd (fromExpr indent Atomic function)
403 (anyMany, argsB) = linesMap (fromExpr deeperIndent Whatever) args
406 funcB <> "(\n" <> deeperIndent <> commaNewlineSep indent argsB <> ")"
408 funcB <> "(" <> commaSep argsB <> ")"
410 Function maybeName args stmts ->
412 "function " <> maybe mempty Name.toBuilder maybeName <> "(" <> commaSep (map Name.toBuilder args) <> ") {\n"
414 fromStmtBlock (deeper indent) stmts
423fromField :: Builder -> (Name, Expr) -> (Lines, Builder)
424fromField indent (field, expr) =
426 (lines, builder) = fromExpr indent Whatever expr
429 , Name.toBuilder field <> ": " <> builder
437fromLValue :: Builder -> LValue -> (Lines, Builder)
438fromLValue indent lValue =
441 (One, Name.toBuilder name)
444 makeDot indent expr field
446 LBracket expr bracketedExpr ->
447 makeBracketed indent expr bracketedExpr
450makeDot :: Builder -> Expr -> Name -> (Lines, Builder)
451makeDot indent expr field =
453 (lines, builder) = fromExpr indent Atomic expr
455 (lines, builder <> "." <> Name.toBuilder field)
458makeBracketed :: Builder -> Expr -> Expr -> (Lines, Builder)
459makeBracketed indent expr bracketedExpr =
461 (lines , builder ) = fromExpr indent Atomic expr
462 (bracketedLines, bracketedBuilder) = fromExpr indent Whatever bracketedExpr
464 ( merge lines bracketedLines
465 , builder <> "[" <> bracketedBuilder <> "]"
473fromPrefix :: PrefixOp -> Builder
478 PrefixComplement -> "~"
481fromInfix :: InfixOp -> Builder
497 OpBitwiseAnd -> " & "
498 OpBitwiseXor -> " ^ "
502 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