-
-
Notifications
You must be signed in to change notification settings - Fork 419
/
Copy pathscope.c
376 lines (307 loc) · 9.12 KB
/
scope.c
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
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
#include "scope.h"
#include "../type/assemble.h"
#include "../pkg/package.h"
#include "../pkg/use.h"
#include "../ast/symtab.h"
#include "../ast/token.h"
#include "../ast/stringtab.h"
#include "../ast/astbuild.h"
#include "../ast/id.h"
#include "ponyassert.h"
#include <string.h>
/**
* Insert a name->AST mapping into the specified scope.
*/
static bool set_scope(pass_opt_t* opt, ast_t* scope, ast_t* name, ast_t* value,
bool allow_shadowing)
{
pony_assert(ast_id(name) == TK_ID);
const char* s = ast_name(name);
if(is_name_dontcare(s))
return true;
sym_status_t status = SYM_NONE;
switch(ast_id(value))
{
case TK_TYPE:
case TK_INTERFACE:
case TK_TRAIT:
case TK_PRIMITIVE:
case TK_STRUCT:
case TK_CLASS:
case TK_ACTOR:
case TK_TYPEPARAM:
case TK_PACKAGE:
case TK_NEW:
case TK_BE:
case TK_FUN:
break;
case TK_VAR:
case TK_LET:
status = SYM_UNDEFINED;
break;
case TK_FVAR:
case TK_FLET:
case TK_EMBED:
case TK_PARAM:
case TK_MATCH_CAPTURE:
status = SYM_DEFINED;
break;
default:
pony_assert(0);
return false;
}
if(!ast_set(scope, s, value, status, allow_shadowing))
{
ast_t* prev = ast_get(scope, s, NULL);
ast_t* prev_nocase = ast_get_case(scope, s, NULL);
ast_error(opt->check.errors, name, "can't reuse name '%s'", s);
ast_error_continue(opt->check.errors, prev_nocase,
"previous use of '%s'%s",
s, (prev == NULL) ? " differs only by case" : "");
return false;
}
return true;
}
bool use_package(ast_t* ast, const char* path, ast_t* name,
pass_opt_t* options)
{
pony_assert(ast != NULL);
pony_assert(path != NULL);
ast_t* package = package_load(ast, path, options);
if(package == NULL)
{
ast_error(options->check.errors, ast, "can't load package '%s'", path);
return false;
}
// Store the package so we can import it later without having to look it up
// again
ast_setdata(ast, (void*)package);
ast_t* curr_package = ast_nearest(ast, TK_PACKAGE);
pony_assert(curr_package != NULL);
package_add_dependency(curr_package, package);
if(name != NULL && ast_id(name) == TK_ID) // We have an alias
return set_scope(options, ast, name, package, false);
ast_setflag(ast, AST_FLAG_IMPORT);
return true;
}
static bool scope_method(pass_opt_t* opt, ast_t* ast)
{
ast_t* id = ast_childidx(ast, 1);
if(!set_scope(opt, ast_parent(ast), id, ast, false))
return false;
return true;
}
static ast_result_t scope_entity(pass_opt_t* opt, ast_t* ast)
{
AST_GET_CHILDREN(ast, id, typeparams, cap, provides, members);
if(!set_scope(opt, opt->check.frame->package, id, ast, false))
return AST_ERROR;
// Scope fields and methods immediately, so that the contents of method
// signatures and bodies cannot shadow fields and methods.
ast_t* member = ast_child(members);
while(member != NULL)
{
switch(ast_id(member))
{
case TK_FVAR:
case TK_FLET:
case TK_EMBED:
if(!set_scope(opt, member, ast_child(member), member, false))
return AST_ERROR;
break;
case TK_NEW:
case TK_BE:
case TK_FUN:
if(!scope_method(opt, member))
return AST_ERROR;
break;
default:
pony_assert(0);
return AST_FATAL;
}
member = ast_sibling(member);
}
return AST_OK;
}
static ast_t* make_iftype_typeparam(pass_opt_t* opt, ast_t* subtype,
ast_t* supertype, ast_t* scope)
{
pony_assert(ast_id(subtype) == TK_NOMINAL);
const char* name = ast_name(ast_childidx(subtype, 1));
ast_t* def = ast_get(scope, name, NULL);
if(def == NULL)
{
ast_error(opt->check.errors, ast_child(subtype),
"can't find definition of '%s'", name);
return NULL;
}
if(ast_id(def) != TK_TYPEPARAM)
{
ast_error(opt->check.errors, subtype, "the subtype in an iftype condition "
"must be a type parameter or a tuple of type parameters");
return NULL;
}
ast_t* current_constraint = ast_childidx(def, 1);
ast_t* new_constraint = ast_dup(supertype);
if((ast_id(current_constraint) != TK_NOMINAL) ||
(ast_name(ast_childidx(current_constraint, 1)) != name))
{
// If the constraint is the type parameter itself, there is no constraint.
// We can't use type_isect to build the new constraint because we don't have
// full type information yet.
BUILD(isect, new_constraint,
NODE(TK_ISECTTYPE,
TREE(ast_dup(current_constraint))
TREE(new_constraint)));
new_constraint = isect;
}
BUILD(typeparam, def,
NODE(TK_TYPEPARAM,
ID(name)
TREE(new_constraint)
NONE));
// keep data pointing to the original def
ast_setdata(typeparam, ast_data(def));
return typeparam;
}
static ast_result_t scope_iftype(pass_opt_t* opt, ast_t* ast)
{
pony_assert(ast_id(ast) == TK_IFTYPE);
AST_GET_CHILDREN(ast, subtype, supertype, body, typeparam_store);
ast_t* typeparams = ast_from(ast, TK_TYPEPARAMS);
switch(ast_id(subtype))
{
case TK_NOMINAL:
{
ast_t* typeparam = make_iftype_typeparam(opt, subtype, supertype, ast);
if(typeparam == NULL)
{
ast_free_unattached(typeparams);
return AST_ERROR;
}
if(!set_scope(opt, ast, ast_child(typeparam), typeparam, true))
{
ast_free_unattached(typeparams);
return AST_ERROR;
}
ast_add(typeparams, typeparam);
break;
}
case TK_TUPLETYPE:
{
if(ast_id(supertype) != TK_TUPLETYPE)
{
ast_error(opt->check.errors, subtype, "iftype subtype is a tuple but "
"supertype isn't");
ast_error_continue(opt->check.errors, supertype, "Supertype is %s",
ast_print_type(supertype));
ast_free_unattached(typeparams);
return AST_ERROR;
}
if(ast_childcount(subtype) != ast_childcount(supertype))
{
ast_error(opt->check.errors, subtype, "the subtype and the supertype "
"in an iftype condition must have the same cardinality");
ast_free_unattached(typeparams);
return AST_ERROR;
}
ast_t* sub_child = ast_child(subtype);
ast_t* super_child = ast_child(supertype);
while(sub_child != NULL)
{
ast_t* typeparam = make_iftype_typeparam(opt, sub_child, super_child,
ast);
if(typeparam == NULL)
{
ast_free_unattached(typeparams);
return AST_ERROR;
}
if(!set_scope(opt, ast, ast_child(typeparam), typeparam, true))
{
ast_free_unattached(typeparams);
return AST_ERROR;
}
ast_add(typeparams, typeparam);
sub_child = ast_sibling(sub_child);
super_child = ast_sibling(super_child);
}
break;
}
default:
ast_error(opt->check.errors, subtype, "the subtype in an iftype "
"condition must be a type parameter or a tuple of type parameters");
ast_free_unattached(typeparams);
return AST_ERROR;
}
// We don't want the scope pass to run on typeparams. The compiler would think
// that type parameters are declared twice.
ast_pass_record(typeparams, PASS_SCOPE);
pony_assert(ast_id(typeparam_store) == TK_NONE);
ast_replace(&typeparam_store, typeparams);
return AST_OK;
}
static bool scope_call(pass_opt_t* opt, ast_t* ast)
{
pony_assert(ast_id(ast) == TK_CALL);
AST_GET_CHILDREN(ast, lhs, positional, named, question);
// Run the args before the receiver, so that symbol status tracking
// will have their scope names defined in the args first.
if(!ast_passes_subtree(&positional, opt, PASS_SCOPE) ||
!ast_passes_subtree(&named, opt, PASS_SCOPE))
return false;
return true;
}
static bool scope_assign(pass_opt_t* opt, ast_t* ast)
{
pony_assert(ast_id(ast) == TK_ASSIGN);
AST_GET_CHILDREN(ast, left, right);
// Run the right side before the left side, so that symbol status tracking
// will have their scope names defined in the right side first.
if(!ast_passes_subtree(&right, opt, PASS_SCOPE))
return false;
return true;
}
ast_result_t pass_scope(ast_t** astp, pass_opt_t* options)
{
ast_t* ast = *astp;
switch(ast_id(ast))
{
case TK_USE:
return use_command(ast, options);
case TK_TYPE:
case TK_INTERFACE:
case TK_TRAIT:
case TK_PRIMITIVE:
case TK_STRUCT:
case TK_CLASS:
case TK_ACTOR:
return scope_entity(options, ast);
case TK_VAR:
case TK_LET:
case TK_PARAM:
case TK_MATCH_CAPTURE:
if(!set_scope(options, ast, ast_child(ast), ast, false))
return AST_ERROR;
break;
case TK_TYPEPARAM:
if(!set_scope(options, ast, ast_child(ast), ast, false))
return AST_ERROR;
// Store the original definition of the typeparam in the data field here.
// It will be retained later if the typeparam def is copied via ast_dup.
if(ast_data(ast) == NULL)
ast_setdata(ast, ast);
break;
case TK_IFTYPE:
return scope_iftype(options, ast);
case TK_CALL:
if(!scope_call(options, ast))
return AST_ERROR;
break;
case TK_ASSIGN:
if(!scope_assign(options, ast))
return AST_ERROR;
break;
default: {}
}
return AST_OK;
}