-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathTerm.hs
180 lines (160 loc) · 5.16 KB
/
Term.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
174
175
176
177
178
179
180
{-# LANGUAGE OverloadedStrings #-}
module Term
( Term(..)
, Operator(..)
, Pattern(..)
, pretty
, mapSourcePos
, sourcePosPretty
, SourcePos
) where
import Identifier (Identifier)
import qualified Identifier
import Data.Text (Text)
import qualified Data.Text as T
import Data.Functor ()
import Text.Megaparsec.Pos (SourcePos, sourcePosPretty)
data Term
= Bool !SourcePos !Bool
| Int !SourcePos !Integer
| If !SourcePos Term Term Term
| Match !SourcePos Term [(Pattern, Term)]
| Variable !SourcePos !Identifier
| Lambda !SourcePos !Identifier Term
| Apply !SourcePos Term Term
| BinOp !SourcePos !Operator Term Term
| Let !SourcePos !Identifier Term Term
| Def !SourcePos !Identifier !Identifier Term Term
| List !SourcePos [Term]
| Tuple !SourcePos [Term]
deriving (Show, Eq)
data Operator
= Add -- '+'
| Sub -- '-'
| Mul -- '*'
| Div -- '/'
| And -- '&&'
| Or -- '||'
| Equal -- '=='
deriving (Show, Eq)
data Pattern
= PBool !SourcePos !Bool
| PInt !SourcePos !Integer
| PVar !SourcePos !Identifier
| PTuple !SourcePos [Pattern]
deriving (Show, Eq)
mapSourcePos :: (SourcePos -> SourcePos) -> Term -> Term
mapSourcePos f term =
case term of
Bool sp bool -> Bool (f sp) bool
Int sp nat -> Int (f sp) nat
If sp c t e -> If (f sp) (mapSourcePos f c) (mapSourcePos f t) (mapSourcePos f e)
Match sp expr arms -> Match (f sp) (mapSourcePos f expr) (map (\(p, t) -> (p, mapSourcePos f t)) arms)
Variable sp i -> Variable (f sp) i
Lambda sp a b -> Lambda (f sp) a (mapSourcePos f b)
Apply sp fn a -> Apply (f sp) (mapSourcePos f fn) (mapSourcePos f a)
BinOp sp op t1 t2 -> BinOp (f sp) op (mapSourcePos f t1) (mapSourcePos f t2)
Let sp vn ve b -> Let (f sp) vn (mapSourcePos f ve) (mapSourcePos f b)
Def sp name arg expr b -> Def (f sp) name arg (mapSourcePos f expr) (mapSourcePos f b)
List sp terms -> List (f sp) (map (mapSourcePos f) terms)
Tuple sp terms -> Tuple (f sp) (map (mapSourcePos f) terms)
pretty :: Int -> Term -> Text
pretty indentLevel term =
case term of
Bool _ bool ->
T.pack (show bool)
Int _ nat ->
T.pack (show nat)
If _ condTerm thenTerm elseTerm ->
"(IF "
<> pretty (indentLevel + 1) condTerm
<> "\n"
<> indent indentLevel
<> pretty (indentLevel + 1) thenTerm
<> "\n"
<> indent indentLevel
<> pretty (indentLevel + 1) elseTerm
<> ")"
Match _ expr arms ->
let
prettyArm (p, t) =
"| " <> patternPretty p <> " -> " <> pretty (indentLevel + 1) t
in
"(MATCH "
<> pretty (indentLevel + 1) expr
<> "\n"
<> T.intercalate "\n" (map prettyArm arms)
<> "\n)"
Variable _ identifier ->
Identifier.name identifier
Lambda _ argumentName body ->
"(LAMBDA "
<> Identifier.name argumentName
<> " .\n"
<> indent indentLevel
<> pretty (indentLevel + 1) body
<> ")"
Apply _ function argument ->
"(APPLY \n"
<> indent indentLevel
<> pretty (indentLevel + 1) function
<> "\n"
<> indent indentLevel
<> pretty (indentLevel + 1) argument
<> ")"
BinOp _ operator lhs rhs ->
"("
<> pretty indentLevel lhs
<> " "
<> operatorPretty operator
<> " "
<> pretty indentLevel rhs
<> ")"
Let _ name expr body ->
"LET "
<> Identifier.name name
<> " =\n"
<> indent indentLevel
<> pretty (indentLevel + 1) expr
<> "\n"
<> indent indentLevel
<> "IN\n"
<> indent indentLevel
<> pretty (indentLevel + 1) body
Def _ name arg expr body ->
"DEF "
<> Identifier.name name
<> " "
<> Identifier.name arg
<> "\n"
<> indent indentLevel
<> pretty (indentLevel + 1) expr
<> "\n"
<> indent indentLevel
<> "IN\n"
<> indent indentLevel
<> pretty (indentLevel + 1) body
List _ elements ->
"LIST ["
<> T.intercalate "," (map (pretty (indentLevel + 1)) elements)
<> "]"
Tuple _ elements ->
"TUPLE ("
<> T.intercalate "," (map (pretty (indentLevel + 1)) elements)
<> ")"
operatorPretty :: Operator -> Text
operatorPretty operator =
case operator of
Add -> "+"
Sub -> "-"
Mul -> "*"
Div -> "/"
And -> "&&"
Or -> "||"
Equal -> "=="
patternPretty :: Pattern -> Text
patternPretty pattern_ =
T.pack (show pattern_)
indent :: Int -> Text
indent level =
T.replicate level "| "