-
Notifications
You must be signed in to change notification settings - Fork 1
/
ASTChangeNames.scala
268 lines (237 loc) · 9.4 KB
/
ASTChangeNames.scala
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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
package ast_change_names
import exceptions._
import frontend._
import toplev.Pass
import toplev.Shared
/* This pass takes the input and restructures the names so that
* all variable names are unique. */
object ASTChangeNames
extends Pass[ASTProgram, ASTProgram]("ast_change_names") {
def changeNames(map: ASTNameEnvironment,
dec: ASTDeclaration): ASTDeclaration = dec match {
case ASTValBind(ident, expression) => {
// Do the expression first.
val newExpression = changeNames(map, expression)
val newIdentifiers = changeNamesInsert(map, ident)
ASTValBind(newIdentifiers.asInstanceOf[ASTIdent], newExpression)
}
case ASTFunBind(cases) => {
// The identifier should be inserted in the parent.
assert(cases.length >= 1)
// Insert the new function name
changeNamesInsert(map, cases(0)._1)
ASTFunBind(cases.map {
case (ident, patterns, types, expression) => {
// All subsequent names may be simply 'changed'
val newIdents = changeNames(map, ident)
val newNameEnv = new ASTNameEnvironment(map)
val newPattern = changeNamesInsert(newNameEnv, patterns)
val newExpression = changeNames(newNameEnv, expression)
val newTypes = types.map(changeNames(map, _))
(newIdents, newPattern, newTypes, newExpression)
}
})
}
case ASTExceptionBind(name, typs) => {
// Add this exception type to the datatype map.
val newName = name match {
case ASTIdentVar(name) => {
val newName = FunctionNameGenerator.newIdentName(name)
map.addDataType(name, newName)
ASTIdentVar(newName)
}
case _ => throw new ICE("Exception with non ASTIdentVar name")
}
// Declaration of this exception is left unchanged. Exceptions
// may not appear in the types of an exception.
ASTExceptionBind(newName, typs.map(changeNames(map, _)))
}
case ASTDataTypeBind(name, typs, dataClass) => {
if (!map.contains(dataClass.name.id)) {
map.add(dataClass.name.id,
FunctionNameGenerator.newIdentName(dataClass.name.id))
}
// Since datatypes may be recursive, we have to be careful to do this
// first.
val newDataClass = changeNames(map, dataClass).asInstanceOf[ASTDataType]
val newTyps = typs.map(changeNames(map, _))
val newName = name match {
case ASTIdentVar(name) => {
val newName = FunctionNameGenerator.newIdentName(name)
map.addDataType(name, newName)
ASTIdentVar(newName)
}
case _ => throw new ICE("Datatype with non ASTIdentVar name")
}
ASTDataTypeBind(newName, newTyps, newDataClass)
}
}
def changeNames(map: ASTNameEnvironment, exp: ASTExp): ASTExp = exp match {
case ASTExpIdent(name) => name match {
case ASTIdentVar(name) => ASTExpIdent(ASTIdentVar(map(name)))
case other => ASTExpIdent(other)
}
case const @ ASTExpConst(_) => const
case ASTExpFunApp(function, application) =>
ASTExpFunApp(changeNames(map, function), changeNames(map, application))
case ASTExpInfixApp(operator, operand1, operand2) =>
ASTExpInfixApp(changeNamesInfixIdent(map, operator),
changeNames(map, operand1),
changeNames(map, operand2))
case ASTExpUnOpApply(operator, operand) =>
ASTExpUnOpApply(changeNamesUnOp(map, operator),
changeNames(map, operand))
case ASTExpTuple(items) =>
ASTExpTuple(items.map(changeNames(map, _)))
case ASTExpList(items) =>
ASTExpList(items.map(changeNames(map, _)))
case ASTExpLetIn(decs, exps) => {
val newMap = new ASTNameEnvironment(map)
// Type the decs the the expression
val newDecs = decs.map(changeNames(newMap, _))
val newExps = exps.map(changeNames(newMap, _))
ASTExpLetIn(newDecs, newExps)
}
case ASTExpSeq(seqs) =>
ASTExpSeq(seqs.map(changeNames(map, _)))
case ASTExpTyped(exp, typ) =>
ASTExpTyped(changeNames(map, exp), changeNames(map, typ))
case ASTExpMatchRow(pats, exp) => {
val newMap = new ASTNameEnvironment(map)
val newPats = pats.map(changeNamesInsert(newMap, _))
val newExp = changeNames(newMap, exp)
ASTExpMatchRow(newPats, newExp)
}
case ASTExpRaise(exception) =>
ASTExpRaise(changeNames(map, exception))
case ASTExpHandle(exp, cases) =>
ASTExpHandle(changeNames(map, exp),
cases.map(changeNamesMatchRow(map, _)))
case ASTExpFn(body) =>
ASTExpFn(body.map(changeNamesMatchRow(map, _)))
case ASTExpIfThenElse(cond, t, f) =>
ASTExpIfThenElse(changeNames(map, cond), changeNames(map, t),
changeNames(map, f))
case ASTExpCase(exp, cases) =>
ASTExpCase(changeNames(map, exp), cases.map(changeNamesMatchRow(map, _)))
}
/* If this compiler were to be expanded to a larger subset including
* infix declarations, this pass would have to be rewritten. */
def changeNamesUnOp(map: ASTNameEnvironment, ident: ASTUnOp) =
ident
def changeNamesInfixIdent(map: ASTNameEnvironment, ident: ASTInfixIdent) =
ident
def changeNamesMatchRow(map: ASTNameEnvironment, row: ASTExpMatchRow) =
changeNames(map, row).asInstanceOf[ASTExpMatchRow]
def changeNames(map: ASTNameEnvironment, ident: ASTIdent): ASTIdent =
ident match {
case ASTIdentVar(name) => ASTIdentVar(map(name))
case ASTIdentTuple(list) =>
ASTIdentTuple(list.map(changeNamesInsert(map, _)))
case other => other
}
def changeNamesInsert(map: ASTNameEnvironment, ident: ASTIdent): ASTIdent =
ident match {
case ASTIdentVar(name) => {
val newName = FunctionNameGenerator.newIdentName(name)
map.add(name, newName)
ASTIdentVar(newName)
}
case ASTIdentTuple(list) =>
ASTIdentTuple(list.map(changeNamesInsert(map, _)))
case other => other
}
def changeNamesInsertNoDuplicate(map: ASTNameEnvironment,
ident: ASTIdent): ASTIdent = ident match {
case ASTIdentVar(name) => {
val newName = FunctionNameGenerator.newIdentName(name)
map.addIfNew(name, newName)
ASTIdentVar(newName)
}
case ASTIdentTuple(list) =>
ASTIdentTuple(list.map(changeNamesInsert(map, _)))
case other => other
}
def changeNamesInsert(map: ASTNameEnvironment,
pattern: List[ASTPat]): List[ASTPat] =
pattern.map(changeNamesInsert(map, _))
/* In this method, we must be careful to account for doubly named
* elements. */
def changeNamesInsert(map: ASTNameEnvironment, pattern: ASTPat): ASTPat =
pattern match {
case ASTPatVariable(variable, typ) =>
if (variable.isInstanceOf[ASTIdentVar] &&
map.isDataType(variable.asInstanceOf[ASTIdentVar].id)) {
ASTPatConstructor(changeNames(map, variable), None,
changeNames(map, typ))
} else {
ASTPatVariable(changeNamesInsertNoDuplicate(map, variable),
changeNames(map, typ))
}
case ASTPatSeq(pats, typs) =>
ASTPatSeq(pats.map(changeNamesInsert(map, _)), changeNames(map, typs))
case ASTListPat(list, typs) =>
ASTListPat(list.map(changeNamesInsert(map, _)), changeNames(map, typs))
case ASTPatConstructor(name, args, typs) => {
val newName = changeNames(map, name)
ASTPatConstructor(newName,
args.map(changeNamesInsert(map, _)),
changeNames(map, typs))
}
case ASTPatCons(head, tail, typs) =>
ASTPatCons(changeNamesInsert(map, head),
changeNamesInsert(map, tail),
changeNames(map, typs))
case other => other
}
def changeNames(map: ASTNameEnvironment,
typList: List[ASTType]): List[ASTType] =
typList.map(changeNames(map, _))
def changeNames(map: ASTNameEnvironment, typ: ASTType): ASTType =
typ match {
case ASTDataTypeName(name) =>
ASTDataTypeName(changeNames(map, name))
case ASTDataType(name) =>
ASTDataType(changeNames(map, name).asInstanceOf[ASTIdentVar])
case ASTFunctionType(from, to) =>
ASTFunctionType(changeNames(map, from),
changeNames(map, to))
case ASTTupleType(elems) =>
if (elems.length == 1) elems(0)
else ASTTupleType(elems.map(changeNames(map, _)))
case ASTListType(subTyp) =>
ASTListType(changeNames(map, subTyp))
case other => other
}
def run(tree: ASTProgram): ASTProgram = {
val substitutionMap = new ASTNameEnvironment()
try {
new ASTProgram(tree.decs.map(changeNames(substitutionMap, _)))
} catch {
case e: UnrecognizedIdentifierError => {
println("Unrecognized identifier")
println(e.getMessage())
if (Shared.debug)
e.printStackTrace()
System.exit(1)
unreachable
}
case e: UnimplementedException => {
println("Datatypes not implemented")
println(e.getMessage())
if (Shared.debug)
e.printStackTrace()
System.exit(1)
unreachable
}
case e: BadPatternException => {
println("Bad pattern error")
println(e.getMessage())
if (Shared.debug)
e.printStackTrace()
System.exit(1)
unreachable
}
}
}
}