1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
------------------------------------------------------------------------------
--- A library to represent JavaScript programs.
---
--- @author Michael Hanus
--- @version November 2020
------------------------------------------------------------------------------

module Language.JavaScript.Show
  ( showJSExp, showJSStat, showJSFDecl )
 where

import Data.List ( intercalate )

import Language.JavaScript.Types

------------------------------------------------------------------------------
--- Shows a JavaScript expression as a string in JavaScript syntax.
showJSExp :: JSExp -> String
showJSExp (JSString s) = "\"" ++ s ++ "\""
showJSExp (JSInt i) = show i
showJSExp (JSBool b) = if b then "true" else "false"
showJSExp (JSIVar i) = "x" ++ show i
showJSExp (JSIArrayIdx ai i) = "x" ++ show ai ++ "[" ++ show i ++ "]"
showJSExp (JSOp op e1 e2) =
  "(" ++ showJSExp e1 ++ " " ++ op ++ " " ++ showJSExp e2 ++ ")"
showJSExp (JSFCall f args) =
  f ++ "(" ++ intercalate "," (map showJSExp args) ++ ")"
showJSExp (JSApply f e) = showJSExp f ++ "(" ++ showJSExp e ++ ")"
showJSExp (JSLambda params body) =
  "function(" ++ intercalate "," (map (showJSExp . JSIVar) params) ++
  ") {" ++ concatMap (showJSStat 1) body ++ "} "

--- Shows a JavaScript statement as a string in JavaScript syntax
--- with indenting.
--- @param i - number of spaces to indent this statement
--- @param jstat - the JavaScript statement to print
showJSStat :: Int -> JSStat -> String
showJSStat i (JSAssign e1 e2) =
  blanks i ++ showJSExp e1 ++ " = " ++ showJSExp e2 ++";"
showJSStat i (JSIf e s1 s2) =
  blanks i ++ "if (" ++ showJSExp e ++ ") {\n" ++
  concatMap (( ++ "\n") . (showJSStat (i+2))) s1  ++
  if null s2
  then blanks i ++ "}"
  else blanks i ++ "} else {\n" ++
       concatMap ((++"\n") . (showJSStat (i+2))) s2 ++
       blanks i ++ "}"
showJSStat i (JSSwitch e bs) =
  blanks i ++ "switch ("++showJSExp e++") {\n"++
  concatMap showJSBranch bs ++
  blanks i ++ "}"
 where
  showJSBranch (JSCase cs bstats) =
     blanks (i+2) ++ "case \"" ++ cs ++ "\" :\n" ++
     concatMap ((++"\n") . (showJSStat (i+4))) bstats ++
     blanks (i+4) ++ "break;\n"
  showJSBranch (JSDefault bstats) =
     blanks (i+2) ++ "default :\n" ++
     concatMap ((++"\n") . (showJSStat (i+4))) bstats

showJSStat i (JSPCall p args) =
  blanks i ++ p ++ "(" ++ intercalate "," (map showJSExp args) ++ ")"
showJSStat i (JSReturn e) = blanks i ++ "return " ++ showJSExp e ++";"
showJSStat i (JSVarDecl vi) = blanks i ++ "var x" ++ show vi ++";"

blanks :: Int -> String
blanks n = replicate n ' '

--- Shows a JavaScript function declaration as a string in JavaScript syntax.
showJSFDecl :: JSFDecl -> String
showJSFDecl (JSFDecl f args body) =
  "function " ++ f ++ "(" ++
      intercalate "," (map showJSExp (map JSIVar args)) ++ ") {\n" ++
  concatMap (( ++ "\n") . (showJSStat 2)) body ++ "}\n\n"

------------------------------------------------------------------------------