-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathJavaScriptSyntax.hs
108 lines (96 loc) · 3.27 KB
/
JavaScriptSyntax.hs
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
{-# LANGUAGE OverloadedStrings #-}
module JavaScriptSyntax
( printModule
) where
import Data.List (intercalate)
import qualified Data.List.NonEmpty as NE
import Data.List.NonEmpty (toList)
import Data.Semigroup
import Data.Text (Text)
import qualified Data.Text as T
import Language
showT :: Show a => a -> Text
showT = T.pack . show
indent :: Int -> Text -> Text
indent level str =
T.intercalate "\n" $
map (\line -> T.replicate level " " <> line) (T.lines str)
indent2 :: Text -> Text
indent2 = indent 2
printModule :: Module -> Text
printModule (Module topLevels) =
(T.intercalate "\n\n" $ map printTopLevel topLevels) <> "\n"
printTopLevel :: TopLevel -> Text
printTopLevel topLevel =
case topLevel of
Function declaration -> printDeclaration declaration
DataType (ADT name generics ctors) ->
"type " <> s name <> printedGenerics <> " =" <>
indent 2 printedCtors
where printedGenerics =
case generics of
[] -> ""
_ -> "<" <> T.intercalate ", " (s <$> generics) <> ">"
printedCtors = T.intercalate " | " (printCtor <$> (NE.toList ctors))
printCtor (Constructor name maybeType) =
s name <> " " <> maybe "" printConstructorType maybeType
printConstructorType ctorType =
case ctorType of
CTConcrete i -> s i
CTApplied a b ->
printConstructorType a <> " " <> printConstructorType b
CTParenthesized ct -> parens (printConstructorType ct)
printDeclaration :: Declaration -> Text
printDeclaration (Declaration _ name args expression) =
"function " <> s name <> printedArgs <> " {\n return " <>
printExpression expression <>
"\n}"
where
printedArgs = parens $ T.intercalate ", " $ map printArgument args
printExpression :: Expression -> Text
printExpression expression =
case expression of
Number number -> showT number
Float f -> showT f
Identifier identifier -> s identifier
Infix operator a b ->
T.intercalate
" "
[printExpression a, printOperator operator, printExpression b]
String' string -> showT string
Apply a b -> printExpression a <> parens (printExpression b)
BetweenParens expression -> parens $ printExpression expression
Case expression branches ->
"switch " <> parens (printExpression expression) <> " {\n" <>
indent 4 (printBranches branches) <>
"\n }"
Let declarations expr ->
indent
2
(T.intercalate
"\n"
((printDeclaration <$>
(NE.toList declarations)) <> [printExpression expr]))
where
printBranches branches =
T.intercalate "\n" $ toList $ fmap printBranch branches
printBranch (condition, body) =
"case " <> printArgument condition <> ":\n" <>
indent2 (printExpression body)
printArgument :: Argument -> Text
printArgument a =
case a of
AIdentifier n -> s n
ADeconstruction name args ->
s name <> parens (T.intercalate ", " (printArgument <$> args))
ANumberLiteral i -> showT i
printOperator :: OperatorExpr -> Text
printOperator operator =
case operator of
Add -> "+"
Subtract -> "-"
Divide -> "/"
Multiply -> "*"
StringAdd -> "++"
parens :: Text -> Text
parens s = "(" <> s <> ")"