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 qualified Data.ByteString as BS
20import Data.ByteString.Builder as B
21import Data.Monoid ((<>))
22import qualified Generate.JavaScript.Name as Name
23import Generate.JavaScript.Name (Name)
24import qualified Json.Encode as Json
39 | Object [(Name, Expr)]
41 | Access Expr Name -- foo.bar
42 | Index Expr Expr -- foo[bar]
43 | Prefix PrefixOp Expr
44 | Infix InfixOp Expr Expr
48 | Function (Maybe Name) [Name] [Stmt]
65 | IfStmt Expr Stmt Stmt
69 | Continue (Maybe Name)
76 | FunctionStmt Name [Name] [Stmt]
113 | PrefixComplement -- ~
120stmtToBuilder :: Stmt -> Builder
122 fromStmt levelZero stmts
125exprToBuilder :: Expr -> Builder
127 snd $ fromExpr levelZero Whatever expr
140 Level mempty (makeLevel 1 (BS.replicate 16 0x09 {-\t-}))
143makeLevel :: Int -> BS.ByteString -> Level
144makeLevel level oldTabs =
147 if level <= BS.length oldTabs
149 else BS.replicate (BS.length oldTabs * 2) 0x09 {-\t-}
151 Level (B.byteString (BS.take level tabs)) (makeLevel (level + 1) tabs)
158commaSep :: [Builder] -> Builder
160 mconcat (List.intersperse ", " builders)
163commaNewlineSep :: Level -> [Builder] -> Builder
164commaNewlineSep (Level _ (Level deeperIndent _)) builders =
165 mconcat (List.intersperse (",\n" <> deeperIndent) builders)
172fromStmtBlock :: Level -> [Stmt] -> Builder
173fromStmtBlock level stmts =
174 mconcat (map (fromStmt level) stmts)
177fromStmt :: Level -> Stmt -> Builder
178fromStmt level@(Level indent nextLevel) statement =
181 fromStmtBlock level stmts
187 indent <> snd (fromExpr level Whatever expr) <> ";\n"
189 IfStmt condition thenStmt elseStmt ->
191 [ indent, "if (", snd (fromExpr level Whatever condition), ") {\n"
192 , fromStmt nextLevel thenStmt
193 , indent, "} else {\n"
194 , fromStmt nextLevel elseStmt
198 Switch expr clauses ->
200 [ indent, "switch (", snd (fromExpr level Whatever expr), ") {\n"
201 , mconcat (map (fromClause nextLevel) clauses)
207 [ indent, "while (", snd (fromExpr level Whatever expr), ") {\n"
208 , fromStmt nextLevel stmt
215 Break (Just label) ->
216 indent <> "break " <> Name.toBuilder label <> ";\n"
219 indent <> "continue;\n"
221 Continue (Just label) ->
222 indent <> "continue " <> Name.toBuilder label <> ";\n"
224 Labelled label stmt ->
226 [ indent, Name.toBuilder label, ":\n"
227 , fromStmt level stmt
230 Try tryStmt errorName catchStmt ->
233 , fromStmt nextLevel tryStmt
234 , indent, "} catch (", Name.toBuilder errorName, ") {\n"
235 , fromStmt nextLevel catchStmt
240 indent <> "throw " <> snd (fromExpr level Whatever expr) <> ";"
243 indent <> "return " <> snd (fromExpr level Whatever expr) <> ";\n"
246 indent <> "var " <> Name.toBuilder name <> " = " <> snd (fromExpr level Whatever expr) <> ";\n"
252 indent <> "var " <> commaNewlineSep level (map (varToBuilder level) vars) <> ";\n"
254 FunctionStmt name args stmts ->
255 indent <> "function " <> Name.toBuilder name <> "(" <> commaSep (map Name.toBuilder args) <> ") {\n"
257 fromStmtBlock nextLevel stmts
266fromClause :: Level -> Case -> Builder
267fromClause level@(Level indent nextLevel) clause =
270 indent <> "case " <> snd (fromExpr level Whatever expr) <> ":\n"
271 <> fromStmtBlock nextLevel stmts
274 indent <> "default:\n"
275 <> fromStmtBlock nextLevel stmts
282varToBuilder :: Level -> (Name, Expr) -> Builder
283varToBuilder level (name, expr) =
284 Name.toBuilder name <> " = " <> snd (fromExpr level Whatever expr)
291data Lines = One | Many deriving (Eq)
294merge :: Lines -> Lines -> Lines
296 if a == Many || b == Many then Many else One
299linesMap :: (a -> (Lines, b)) -> [a] -> (Bool, [b])
304 ( any ((==) Many . fst) pairs
309data Grouping = Atomic | Whatever
312parensFor :: Grouping -> Builder -> Builder
313parensFor grouping builder =
316 "(" <> builder <> ")"
322fromExpr :: Level -> Grouping -> Expr -> (Lines, Builder)
323fromExpr level@(Level indent nextLevel@(Level deeperIndent _)) grouping expression =
326 ( One, "'" <> string <> "'" )
335 ( One, if bool then "true" else "false" )
341 ( One, Json.encodeUgly json )
346 (anyMany, builders) = linesMap (fromExpr level Whatever) exprs
351 <> commaNewlineSep level builders
352 <> "\n" <> indent <> "]"
354 "[" <> commaSep builders <> "]"
359 (anyMany, builders) = linesMap (fromField nextLevel) fields
364 <> commaNewlineSep level builders
365 <> "\n" <> indent <> "}"
367 "{" <> commaSep builders <> "}"
370 ( One, Name.toBuilder name )
373 makeDot level expr field
375 Index expr bracketedExpr ->
376 makeBracketed level expr bracketedExpr
380 (lines, builder) = fromExpr level Atomic expr
383 , parensFor grouping (fromPrefix op <> builder)
386 Infix op leftExpr rightExpr ->
388 (leftLines , left ) = fromExpr level Atomic leftExpr
389 (rightLines, right) = fromExpr level Atomic rightExpr
391 ( merge leftLines rightLines
392 , parensFor grouping (left <> fromInfix op <> right)
395 If condExpr thenExpr elseExpr ->
397 condB = snd (fromExpr level Atomic condExpr)
398 thenB = snd (fromExpr level Atomic thenExpr)
399 elseB = snd (fromExpr level Atomic elseExpr)
402 , parensFor grouping (condB <> " ? " <> thenB <> " : " <> elseB)
405 Assign lValue expr ->
407 (leftLines , left ) = fromLValue level lValue
408 (rightLines, right) = fromExpr level Whatever expr
410 ( merge leftLines rightLines
411 , parensFor grouping (left <> " = " <> right)
414 Call function args ->
417 (_ , funcB) = fromExpr level Atomic function
418 (anyMany, argsB) = linesMap (fromExpr nextLevel Whatever) args
421 funcB <> "(\n" <> deeperIndent <> commaNewlineSep level argsB <> ")"
423 funcB <> "(" <> commaSep argsB <> ")"
425 Function maybeName args stmts ->
427 "function " <> maybe mempty Name.toBuilder maybeName <> "(" <> commaSep (map Name.toBuilder args) <> ") {\n"
429 fromStmtBlock nextLevel stmts
438fromField :: Level -> (Name, Expr) -> (Lines, Builder)
439fromField level (field, expr) =
441 (lines, builder) = fromExpr level Whatever expr
444 , Name.toBuilder field <> ": " <> builder
452fromLValue :: Level -> LValue -> (Lines, Builder)
453fromLValue level lValue =
456 (One, Name.toBuilder name)
459 makeDot level expr field
461 LBracket expr bracketedExpr ->
462 makeBracketed level expr bracketedExpr
465makeDot :: Level -> Expr -> Name -> (Lines, Builder)
466makeDot level expr field =
468 (lines, builder) = fromExpr level Atomic expr
470 (lines, builder <> "." <> Name.toBuilder field)
473makeBracketed :: Level -> Expr -> Expr -> (Lines, Builder)
474makeBracketed level expr bracketedExpr =
476 (lines , builder ) = fromExpr level Atomic expr
477 (bracketedLines, bracketedBuilder) = fromExpr level Whatever bracketedExpr
479 ( merge lines bracketedLines
480 , builder <> "[" <> bracketedBuilder <> "]"
488fromPrefix :: PrefixOp -> Builder
493 PrefixComplement -> "~"
496fromInfix :: InfixOp -> Builder
512 OpBitwiseAnd -> " & "
513 OpBitwiseXor -> " ^ "
517 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