-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathSyntax.hs
173 lines (130 loc) · 4.53 KB
/
Syntax.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
module Syntax where
import qualified Text.Parsec.Pos as Pos
import qualified Text.PrettyPrint as PP
type Ident = String
type Position = Pos.SourcePos
data Expression = LitExpr
{ pos :: Position
, value :: Integer }
| VarExpr
{ pos :: Position
, name :: Ident }
| CallExpr
{ pos :: Position
, func :: Ident
, callArgs :: [Expression] }
| LetExpr
{ letDecl :: Declaration
, letBody :: Expression }
| IfExpr
{ pos :: Position
, condExpr :: Expression
, thenExpr :: Expression
, elseExpr :: Expression }
| SeqExpr
{ fstExp :: Expression
, sndExp :: Expression }
| UnOpExpr
{ pos :: Position
, unaryOp :: Ident
, argExpr :: Expression }
| BinOpExpr
{ binaryOp :: Ident
, lhsExpr :: Expression
, rhsExpr :: Expression }
| MemIndexExpr
{ pos :: Position
, indexExpr :: Expression }
| AssignExpr
{ asgnLhs :: Expression
, asgnRhs :: Expression }
data DeclType = DefDecl | ArgDecl
data Declaration = Declaration
{ declPos :: Position
, declType :: DeclType
, declIdent :: Ident
, declArgs :: [Ident]
, declBody :: Expression }
instance Eq Declaration where
d1 == d2 = declPos d1 == declPos d2
&& declIdent d1 == declIdent d2
declArity :: Declaration -> Int
declArity = length . declArgs
makeDecl pos ident args body = Declaration
{ declPos = pos
, declType = DefDecl
, declIdent = ident
, declArgs = args
, declBody = body }
makeArgDecl pos ident = Declaration
{ declPos = pos
, declType = ArgDecl
, declIdent = ident
, declArgs = []
, declBody = VarExpr pos ident }
-- body does not matter for args
fakeDecl = makeArgDecl (Pos.initialPos "") "$"
data Program = Program
{ decls :: [Declaration]
, mainExpr :: Expression }
infixl 6 <+>
(<+>) = (PP.<+>)
(<>) = (PP.<>)
infixl 5 $$, $+$
($$) = (PP.$$)
($+$) = (PP.$+$)
programToDoc prog =
(PP.vcat $ map (\d -> declToDoc d $$ PP.text "") (decls prog))
$+$
PP.text "return" <+> exprToDoc False (mainExpr prog)
declToDoc decl =
let head = PP.text "let" <+> PP.text (declIdent decl)
<+> PP.hsep (map PP.text (declArgs decl))
<+> PP.text "="
in
case (declBody decl) of
e@(LetExpr _ _) -> head $$ PP.nest 4 (exprToDoc False e)
e -> head <+> exprToDoc False e
exprToDoc _ (LitExpr _ v) = PP.text $ show v
exprToDoc _ (VarExpr _ id) = PP.text id
exprToDoc isArg(CallExpr _ func args) =
inParens isArg $
PP.text func <+> PP.hsep (map (exprToDoc True) args)
exprToDoc isArg (LetExpr decl body) =
inParens isArg $
declToDoc decl $+$
PP.text "in" <+>
exprToDoc False body
exprToDoc isArg (IfExpr _ cond texp fexp) =
inParens isArg $
PP.text "if" <+> exprToDoc False cond <+>
PP.text "then" <+> exprToDoc False texp $$
PP.text "else" <+> exprToDoc False fexp
exprToDoc isArg (SeqExpr exp1 exp2) =
inParens isArg $
exprToDoc False exp1 <+>
PP.text ";" $+$
exprToDoc False exp2
exprToDoc isArg (UnOpExpr _ op arg) =
inParens isArg $
PP.text op <+> exprToDoc True arg
exprToDoc isArg (BinOpExpr op lhs rhs) =
inParens isArg $
exprToDoc True lhs <+>
PP.text op <+>
exprToDoc True rhs
exprToDoc isArg (MemIndexExpr _ indexExp) =
PP.text "[" <> exprToDoc False indexExp <> PP.text "]"
exprToDoc isArg (AssignExpr lhsExp rhsExp) =
inParens isArg $
exprToDoc True lhsExp <+>
PP.text ":=" <+>
exprToDoc True rhsExp
inParens True doc = PP.text "(" <+> doc <+> PP.text ")"
inParens False doc = doc
instance Show Program where
show = PP.render . programToDoc
instance Show Declaration where
show = PP.render . declToDoc
instance Show Expression where
show = PP.render . exprToDoc False