-
Notifications
You must be signed in to change notification settings - Fork 0
/
PufAST.hs
141 lines (118 loc) · 4.64 KB
/
PufAST.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
module PufAST (AST(..), Builtin(..), LDecl(..), RDecl(..), ppAST) where
import Text.PrettyPrint.Leijen
-- Abstract syntax tree parametrized over the type of variables
data AST a
= Var a -- variables (normally Srings)
| Num Int -- numeric constants
| Prim Builtin -- primitive operators
| Cond (AST a) (AST a) (AST a) -- if-then-else
| Fun a (AST a) -- lambda-abstraction
| App (AST a) (AST a) -- application
| Let [LDecl a] (AST a) -- let
| Rec [RDecl a] (AST a) -- letrec
-- tuples
| Tuple [AST a]
| Select Int (AST a)
-- lists
| Nil
| Cons (AST a) (AST a)
| Case (AST a) (AST a) a a (AST a)
deriving Show
data Builtin -- primitive operators
= UNeg
| UNot
| BAdd
| BSub
| BMul
| BDiv
| BMod
| BEq
| BNe
| BLe
| BLt
| BGe
| BGt
| BOr
| BAnd
deriving Show
data LDecl a
= Sdecl a (AST a) -- simple declaration
| Tdecl [a] (AST a) -- tuple declaration
deriving Show
data RDecl a
= Rdecl a (AST a) -- letrec declaration
deriving Show
-- pretty printing
ppAST :: Show a => AST a -> String
ppAST e = show $ pprogram e
texta :: Show a=> a -> Doc
texta a = text $ filter (\c -> c /= '"' ) $ show a
pprogram (Rec decls a) = vsep $ map prdecl decls
pprogram _ = error "Program not in normal form!"
pprint (Var a) = texta a
pprint (Num a) = int a
pprint (Prim b) = pprim b
pprint (Cond cond i e) = text "if" <+> pprint cond </> text "then"
<$> indent 2 (pprint i) <$> text "else"
<$> indent 2 (pprint e)
pprint (Fun a b) = text "fn" <+> texta a <+> text "->" <+> pprint b
pprint (App (App (Prim UNeg) a) b@(App _ _)) = pprim UNeg <+> pprint a
<+> parens (pprint b)
pprint (App (App (Prim UNot) a) b@(App _ _)) = pprim UNot <+> pprint a
<+> parens (pprint b)
pprint (App (App (Prim p) a) b@(App _ _)) = pprint a <+> pprim p
<+> parens (pprint b)
pprint (App (App (Prim UNeg) a) b) = pprim UNeg <+> pprint a <+> pprint b
pprint (App (App (Prim UNot) a) b) = pprim UNot <+> pprint a <+> pprint b
pprint (App (App (Prim p) a) b) = pprint a <+> pprim p <+> pprint b
pprint (App a inner@(App b c)) = pprint a <+> parens (pprint inner)
pprint (App a b) = pprint a <+> pprint b
pprint (Let decls a) = align (text "let" </> align (vsep (map pldecl decls))
</> (text "in" <+> pprint a))
pprint (Rec decls a) = align (text "letrec" </> align (vsep (map prdecl decls))
</> (text "in" <+> pprint a))
pprint (Tuple a) = align $ parens $ fillSep $ punctuate comma (map pprint a)
pprint (Select i a) = text "#" <> int i <+> pprint a
pprint Nil = text "[]"
pprint cons@(Cons a b)
| endsWithNil b = align $ lbracket <> pprint a <> ppl b
| otherwise = parens $ ppc cons
where ppl Nil = rbracket
ppl (Cons a b) = comma </> pprint a <//> ppl b
ppc (Cons a b) = pprint a <> colon <> ppc b
ppc e = pprint e
endsWithNil Nil = True
endsWithNil (Cons _ b) = endsWithNil b
endsWithNil _ = False
pprint (Case cond empt x y part) = hang 2 (text "case" <+> pprint cond <+> text "of"
<$> fill l (text "[]") <+> text "->"
<+> pprint empt <> semi <$> fill l calt
<+> text "->" <+> pprint part)
where l = length (show calt)
calt = texta x <> colon <> texta y
prdecl :: Show a => RDecl a -> Doc
prdecl (Rdecl a b) = ppdecl a b
pldecl :: Show a => LDecl a -> Doc
pldecl (Sdecl a b) = ppdecl a b
pldecl (Tdecl a b) = parens (fillSep (punctuate comma (map texta a)))
<+> equals <+> pprint b <> semi
ppdecl a b@(Fun _ _) = texta a <+> ppfun b
where ppfun (Fun f a) = texta f <+> ppfun a
ppfun x = equals <+> pprint x <> semi
ppdecl a b = texta a <+> equals <+> pprint b <> semi
pprim b = text (case b of
UNeg -> "neg"
UNot -> "not"
BAdd -> "+"
BSub -> "-"
BMul -> "*"
BDiv -> "/"
BMod -> "%"
BEq -> "=="
BNe -> "/="
BLe -> "<="
BLt -> "<"
BGe -> ">="
BGt -> ">"
BOr -> "||"
BAnd -> "&&")