forked from asutton/waffle
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ast.cpp
327 lines (280 loc) · 8.02 KB
/
ast.cpp
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
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
#include "ast.hpp"
#include "type.hpp"
#include "value.hpp"
#include "lang/debug.hpp"
#include <iostream>
#include <unordered_map>
void
init_nodes() {
// Terms
init_node(def_term, "def");
init_node(init_term, "init");
init_node(ls_term, "ls");
init_node(mkdir_term, "mkdir");
init_node(rmdir_term, "rmdir");
init_node(cd_term, "cd");
init_node(mv_term, "mv");
init_node(unit_term, "unit");
init_node(true_term, "true");
init_node(false_term, "false");
init_node(int_term, "int");
init_node(path_term, "path");//Rishi
init_node(var_term, "var");
init_node(abs_term, "abs");
init_node(app_term, "app");
init_node(tuple_term, "tuple");
init_node(list_term, "list");
init_node(record_term, "record");
init_node(comma_term, "comma");
init_node(proj_term, "proj");
init_node(mem_term, "mem");
// Types
init_node(kind_type, "kind-type");
init_node(unit_type, "unit-type");
init_node(bool_type, "bool-type");
init_node(path_type, "path-type");
init_node(nat_type, "nat-type");
init_node(str_type, "str-type");
init_node(arrow_type, "arrow-type");
init_node(tuple_type, "tuple-type");
init_node(list_type, "list-type");
}
// -------------------------------------------------------------------------- //
// Pretty printing
bool
is_term_literal(Term* t) {
return is_unit(t)
or is_boolean_value(t)
or is_integer_value(t)
or is_string_value(t);
}
bool
is_type_literal(Type* t) {
return is_unit_type(t)
or is_bool_type(t)
or is_nat_type(t)
or is_str_type(t);
}
// Returns true if t is a term literal or type literal.
bool
is_literal(Expr* t) {
if (Term* t0 = as<Term>(t))
return is_term_literal(t0);
if (Type* t0 = as<Type>(t))
return is_type_literal(t0);
return false;
}
// Returns true when t is a reference.
bool
is_identifier(Expr* t) {
return t->kind == ref_term;
}
// Returns true if t is a terminal node. In the simply typed
// lambda calculus this is true for only varirables and base
// types. This is usd to determine when to put parens around
// a term when pretty printing.
bool
is_terminal(Expr* t) {
return is_literal(t) || t->kind == ref_term;
}
namespace {
// TODO: This should move into the printing support library.
template<typename T>
void
pp_value(std::ostream& os, const T& x) { os << x; }
void
pp_if(std::ostream& os, If* t) {
os << "if " << group(pretty(t->cond()))
<< " then " << group(pretty(t->if_true()))
<< " else " << group(pretty(t->if_false()));
}
void
pp_succ(std::ostream& os, Succ* t) {
os << "succ " << group(pretty(t->arg()));
}
void
pp_pred(std::ostream& os, Pred* t) {
os << "pred " << group(pretty(t->arg()));
}
void
pp_iszero(std::ostream& os, Iszero* t) {
os << "iszero " << group(pretty(t->arg()));
}
void
pp_var(std::ostream& os, Var* t) {
os << pretty(t->name()) << ':' << pretty(t->type());
}
void
pp_abs(std::ostream& os, Abs* t) {
os << '\\' << pretty(t->var()) << "=>" << group(pretty(t->term()));
}
void
pp_fn(std::ostream& os, Fn* t) {
os << "\\(" << commas(t->parms()) << ")=>" << group(pretty(t->term()));
}
void
pp_app(std::ostream& os, App* t) {
os << '(' << pretty(t->t1) << ' ' << pretty(t->t2) << ')';
}
void
pp_call(std::ostream& os, Call* t) {
os << pretty(t->fn()) << '(' << commas(t->args()) << ')';
}
void
pp_def(std::ostream& os, Def* t) {
os << "def " << pretty(t->name()) << " = " << pretty(t->value());
}
void
pp_ls(std::ostream& os, Ls* t) {
os << "ls " << pretty(t->t1);
}
void
pp_mkdir(std::ostream& os, Mkdir* t) {
os << "mkdir " << pretty(t->t1);
}
void
pp_rmdir(std::ostream& os, Rmdir* t) {
os << "rmdir " << pretty(t->t1);
}
void
pp_cd(std::ostream& os, Cd* t) {
os << "cd " << pretty(t->t1);
}
void
pp_mv(std::ostream& os, Mv* t) {
os << "mv " << pretty(t->t1)<<" "<< pretty(t->t2);
}
void
pp_init(std::ostream& os, Init* t) {
os << pretty(t->name()) << " = " << pretty(t->value());
}
void
pp_tuple(std::ostream& os, Tuple* t) {
os << '{' << commas(t->elems()) << '}';
}
void
pp_list(std::ostream& os, List* t) {
os << '[' << commas(t->elems()) << ']';
}
void
pp_record(std::ostream& os, Record* t) {
os << '{' << commas(t->members()) << '}';
}
void
pp_comma(std::ostream& os, Comma* t) {
os << '(' << commas(t->elems()) << ')';
}
void
pp_proj(std::ostream& os, Proj* t) {
os << pretty(t->tuple()) << '.' << pretty(t->elem());
}
void
pp_mem(std::ostream& os, Mem* t) {
os << pretty(t->record()) << '.' << pretty(t->member());
}
template<typename T>
void
pp_ref_id(std::ostream& os, T* t) {
os << pretty(t->name());
}
// Print the name of the referred to expression.
void
pp_ref(std::ostream& os, Ref* t) {
Expr* e = t->decl();
if (Var* v = as<Var>(e))
return pp_ref_id(os, v);
if (Def* d = as<Def>(e))
return pp_ref_id(os, d);
lang_unreachable(format("print unhandled reference to '{}'", pretty(e)));
}
void
pp_print(std::ostream& os, Print* p) {
os << "print " << pretty(p->expr());
}
void
pp_prog(std::ostream& os, Prog* t) {
for (Term* s : *t->stmts())
os << pretty(s) << ';' << '\n';
}
void
pp_arrow_type(std::ostream& os, Arrow_type* t) {
os << pretty(t->t1) << " -> " << group(pretty(t->t2));
}
void
pp_fn_type(std::ostream& os, Fn_type* t) {
os << '(' << commas(t->parms()) << ")->" << group(pretty(t->result()));
}
void
pp_tuple_type(std::ostream& os, Tuple_type* t) {
os << '{' << commas(t->types()) << '}';
}
void
pp_list_type(std::ostream& os, List_type* t) {
os << '[' << pretty(t->type()) << ']';
}
void
pp_record_type(std::ostream& os, Record_type* t) {
os << '{' << commas(t->members()) << '}';
}
} // namespace
// Render the given term into the output stream.
void
pp_expr(std::ostream& os, Node* t) {
if (not t) {
os << "<null>";
return;
}
switch(t->kind) {
// Names
case id_expr: return pp_terminal(os, as<Id>(t));
// Terms
case unit_term: return pp_string(os, "unit");
case true_term: return pp_string(os, "true");
case false_term: return pp_string(os, "false");
case int_term: return pp_value(os, as<Int>(t)->value());
case str_term: return pp_value(os, as<Str>(t)->value());
case path_term: return pp_value(os, as<Path>(t)->value());
case if_term: return pp_if(os, as<If>(t));
case succ_term: return pp_succ(os, as<Succ>(t));
case ls_term: return pp_ls(os, as<Ls>(t));
case mkdir_term: return pp_mkdir(os, as<Mkdir>(t));
case rmdir_term: return pp_rmdir(os, as<Rmdir>(t));
case cd_term: return pp_cd(os, as<Cd>(t));
case mv_term: return pp_mv(os, as<Mv>(t));
case pred_term: return pp_pred(os, as<Pred>(t));
case iszero_term: return pp_iszero(os, as<Iszero>(t));
case var_term: return pp_var(os, as<Var>(t));
case abs_term: return pp_abs(os, as<Abs>(t));
case fn_term: return pp_fn(os, as<Fn>(t));
case app_term: return pp_app(os, as<App>(t));
case call_term: return pp_call(os, as<Call>(t));
case ref_term: return pp_ref(os, as<Ref>(t));
case def_term: return pp_def(os, as<Def>(t));
case init_term: return pp_init(os, as<Init>(t));
case tuple_term: return pp_tuple(os, as<Tuple>(t));
case list_term: return pp_list(os, as<List>(t));
case record_term: return pp_record(os, as<Record>(t));
case comma_term: return pp_comma(os, as<Comma>(t));
case proj_term: return pp_proj(os, as<Proj>(t));
case print_term: return pp_print(os, as<Print>(t));
case prog_term: return pp_prog(os, as<Prog>(t));
// Types
case unit_type: return pp_string(os, "Unit");
case bool_type: return pp_string(os, "Bool");
case nat_type: return pp_string(os, "Nat");
case str_type: return pp_string(os, "Str");
case path_type: return pp_string(os, "Path");// Rishi
case arrow_type: return pp_arrow_type(os, as<Arrow_type>(t));
case fn_type: return pp_fn_type(os, as<Fn_type>(t));
case tuple_type: return pp_tuple_type(os, as<Tuple_type>(t));
case list_type: return pp_list_type(os, as<List_type>(t));
case record_type: return pp_record_type(os, as<Record_type>(t));
default: break;
}
lang_unreachable(format("print unknown node '{}'", node_name(t)));
}
std::ostream&
operator<<(std::ostream& os, pretty_printer<Expr> t) {
pp_expr(os, t.node);
return os;
}