blob: a715b2b5063578ce8f419af7870855149925f7f6 [file] [log] [blame]
Damien429d7192013-10-04 19:53:11 +01001#include <stdint.h>
2#include <stdio.h>
3#include <string.h>
4#include <assert.h>
5
6#include "misc.h"
7#include "machine.h"
8#include "parse.h"
9#include "scope.h"
10
11scope_t *scope_new(scope_kind_t kind, py_parse_node_t pn) {
12 scope_t *scope = m_new(scope_t, 1);
13 scope->kind = kind;
14 scope->parent = NULL;
15 scope->next = NULL;
16 scope->pn = pn;
17 switch (kind) {
18 case SCOPE_MODULE:
19 scope->simple_name = 0;
20 break;
21 case SCOPE_FUNCTION:
22 case SCOPE_CLASS:
23 assert(PY_PARSE_NODE_IS_STRUCT(pn));
24 scope->simple_name = PY_PARSE_NODE_LEAF_ARG(((py_parse_node_struct_t*)pn)->nodes[0]);
25 break;
26 case SCOPE_LAMBDA:
27 scope->simple_name = qstr_from_str_static("<lambda>");
28 break;
29 case SCOPE_LIST_COMP:
30 scope->simple_name = qstr_from_str_static("<listcomp>");
31 break;
32 case SCOPE_DICT_COMP:
33 scope->simple_name = qstr_from_str_static("<dictcomp>");
34 break;
35 case SCOPE_SET_COMP:
36 scope->simple_name = qstr_from_str_static("<setcomp>");
37 break;
38 case SCOPE_GEN_EXPR:
39 scope->simple_name = qstr_from_str_static("<genexpr>");
40 break;
41 default:
42 assert(0);
43 }
44 scope->id_info_alloc = 8;
45 scope->id_info_len = 0;
46 scope->id_info = m_new(id_info_t, scope->id_info_alloc);
47
48 scope->flags = 0;
49 scope->num_params = 0;
50 /* not needed
51 scope->num_default_params = 0;
52 scope->num_dict_params = 0;
53 */
54 scope->num_locals = 0;
55 scope->unique_code_id = 0;
56
57 return scope;
58}
59
60id_info_t *scope_find_or_add_id(scope_t *scope, qstr qstr, bool *added) {
61 for (int i = 0; i < scope->id_info_len; i++) {
62 if (scope->id_info[i].qstr == qstr) {
63 *added = false;
64 return &scope->id_info[i];
65 }
66 }
67
68 // make sure we have enough memory
69 if (scope->id_info_len >= scope->id_info_alloc) {
70 scope->id_info_alloc *= 2;
71 scope->id_info = m_renew(id_info_t, scope->id_info, scope->id_info_alloc);
72 }
73
74 id_info_t *id_info;
75
76 {
77 /*
78 // just pick next slot in array
79 id_info = &scope->id_info[scope->id_info_len++];
80 */
81 }
82
83 {
84 // sort insert into id_info array, so we are equivalent to CPython (no other reason to do it)
85 scope->id_info_len += 1;
86 for (int i = scope->id_info_len - 1;; i--) {
87 if (i == 0 || strcmp(qstr_str(scope->id_info[i - 1].qstr), qstr_str(qstr)) < 0) {
88 id_info = &scope->id_info[i];
89 break;
90 } else {
91 scope->id_info[i] = scope->id_info[i - 1];
92 }
93 }
94 }
95
96 id_info->param = false;
97 id_info->kind = 0;
98 id_info->qstr = qstr;
99 *added = true;
100 return id_info;
101}
102
103id_info_t *scope_find(scope_t *scope, qstr qstr) {
104 for (int i = 0; i < scope->id_info_len; i++) {
105 if (scope->id_info[i].qstr == qstr) {
106 return &scope->id_info[i];
107 }
108 }
109 return NULL;
110}
111
112id_info_t *scope_find_global(scope_t *scope, qstr qstr) {
113 while (scope->parent != NULL) {
114 scope = scope->parent;
115 }
116 for (int i = 0; i < scope->id_info_len; i++) {
117 if (scope->id_info[i].qstr == qstr) {
118 return &scope->id_info[i];
119 }
120 }
121 return NULL;
122}
123
124id_info_t *scope_find_local_in_parent(scope_t *scope, qstr qstr) {
125 if (scope->parent == NULL) {
126 return NULL;
127 }
128 for (scope_t *s = scope->parent; s->parent != NULL; s = s->parent) {
129 for (int i = 0; i < s->id_info_len; i++) {
130 if (s->id_info[i].qstr == qstr) {
131 return &s->id_info[i];
132 }
133 }
134 }
135 return NULL;
136}
137
138void scope_close_over_in_parents(scope_t *scope, qstr qstr) {
139 assert(scope->parent != NULL); // we should have at least 1 parent
140 for (scope_t *s = scope->parent; s->parent != NULL; s = s->parent) {
141 id_info_t *id = NULL;
142 for (int i = 0; i < s->id_info_len; i++) {
143 if (s->id_info[i].qstr == qstr) {
144 id = &s->id_info[i];
145 break;
146 }
147 }
148 if (id == NULL) {
149 // variable not declared in this scope, so declare it as free and keep searching parents
150 bool added;
151 id = scope_find_or_add_id(s, qstr, &added);
152 assert(added);
153 id->kind = ID_INFO_KIND_FREE;
154 } else {
155 // variable is declared in this scope, so finish
156 switch (id->kind) {
157 case ID_INFO_KIND_LOCAL: id->kind = ID_INFO_KIND_CELL; break; // variable local to this scope, close it over
158 case ID_INFO_KIND_FREE: break; // variable already closed over in a parent scope
159 case ID_INFO_KIND_CELL: break; // variable already closed over in this scope
160 default: assert(0); // TODO
161 }
162 return;
163 }
164 }
165 assert(0); // we should have found the variable in one of the parents
166}
167
168void scope_print_info(scope_t *s) {
169 if (s->kind == SCOPE_MODULE) {
170 printf("code <module>\n");
171 } else if (s->kind == SCOPE_LAMBDA) {
172 printf("code <lambda>\n");
173 } else if (s->kind == SCOPE_LIST_COMP) {
174 printf("code <listcomp>\n");
175 } else if (s->kind == SCOPE_DICT_COMP) {
176 printf("code <dictcomp>\n");
177 } else if (s->kind == SCOPE_SET_COMP) {
178 printf("code <setcomp>\n");
179 } else if (s->kind == SCOPE_GEN_EXPR) {
180 printf("code <genexpr>\n");
181 } else {
182 printf("code %s\n", qstr_str(s->simple_name));
183 }
184 /*
185 printf("var global:");
186 for (int i = 0; i < s->id_info_len; i++) {
187 if (s->id_info[i].kind == ID_INFO_KIND_GLOBAL_EXPLICIT) {
188 printf(" %s", qstr_str(s->id_info[i].qstr));
189 }
190 }
191 printf("\n");
192 printf("var name:");
193 for (int i = 0; i < s->id_info_len; i++) {
194 if (s->id_info[i].kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
195 printf(" %s", qstr_str(s->id_info[i].qstr));
196 }
197 }
198 printf("\n");
199 printf("var local:");
200 for (int i = 0; i < s->id_info_len; i++) {
201 if (s->id_info[i].kind == ID_INFO_KIND_LOCAL) {
202 printf(" %s", qstr_str(s->id_info[i].qstr));
203 }
204 }
205 printf("\n");
206 printf("var free:");
207 for (int i = 0; i < s->id_info_len; i++) {
208 if (s->id_info[i].kind == ID_INFO_KIND_FREE) {
209 printf(" %s", qstr_str(s->id_info[i].qstr));
210 }
211 }
212 printf("\n");
213 */
214 printf(" flags %04x\n", s->flags);
215 printf(" argcount %d\n", s->num_params);
216 printf(" nlocals %d\n", s->num_locals);
217 printf(" stacksize %d\n", s->stack_size);
218}