blob: d55a4ddeaa7fc8a12553cc5bd6fdc7f2abd74d38 [file] [log] [blame]
xbeefe34222014-03-16 00:14:26 -07001#include <stdbool.h>
Damien429d7192013-10-04 19:53:11 +01002#include <stdint.h>
3#include <stdio.h>
Damien429d7192013-10-04 19:53:11 +01004#include <assert.h>
5
6#include "misc.h"
Damiend99b0522013-12-21 18:17:45 +00007#include "mpconfig.h"
Damien George55baff42014-01-21 21:40:13 +00008#include "qstr.h"
Damien429d7192013-10-04 19:53:11 +01009#include "parse.h"
10#include "scope.h"
11
Damien Georgecbd2f742014-01-19 11:48:48 +000012scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, qstr source_file, uint unique_code_id, uint emit_options) {
Damien George78035b92014-04-09 12:27:39 +010013 scope_t *scope = m_new0(scope_t, 1);
Damien429d7192013-10-04 19:53:11 +010014 scope->kind = kind;
Damien429d7192013-10-04 19:53:11 +010015 scope->pn = pn;
Damien Georgecbd2f742014-01-19 11:48:48 +000016 scope->source_file = source_file;
Damien429d7192013-10-04 19:53:11 +010017 switch (kind) {
18 case SCOPE_MODULE:
Paul Sokolovskyab5d0822014-01-24 00:22:00 +020019 scope->simple_name = MP_QSTR__lt_module_gt_;
Damien429d7192013-10-04 19:53:11 +010020 break;
21 case SCOPE_FUNCTION:
22 case SCOPE_CLASS:
Damiend99b0522013-12-21 18:17:45 +000023 assert(MP_PARSE_NODE_IS_STRUCT(pn));
24 scope->simple_name = MP_PARSE_NODE_LEAF_ARG(((mp_parse_node_struct_t*)pn)->nodes[0]);
Damien429d7192013-10-04 19:53:11 +010025 break;
26 case SCOPE_LAMBDA:
Paul Sokolovskyab5d0822014-01-24 00:22:00 +020027 scope->simple_name = MP_QSTR__lt_lambda_gt_;
Damien429d7192013-10-04 19:53:11 +010028 break;
29 case SCOPE_LIST_COMP:
Paul Sokolovskyab5d0822014-01-24 00:22:00 +020030 scope->simple_name = MP_QSTR__lt_listcomp_gt_;
Damien429d7192013-10-04 19:53:11 +010031 break;
32 case SCOPE_DICT_COMP:
Paul Sokolovskyab5d0822014-01-24 00:22:00 +020033 scope->simple_name = MP_QSTR__lt_dictcomp_gt_;
Damien429d7192013-10-04 19:53:11 +010034 break;
35 case SCOPE_SET_COMP:
Paul Sokolovskyab5d0822014-01-24 00:22:00 +020036 scope->simple_name = MP_QSTR__lt_setcomp_gt_;
Damien429d7192013-10-04 19:53:11 +010037 break;
38 case SCOPE_GEN_EXPR:
Paul Sokolovskyab5d0822014-01-24 00:22:00 +020039 scope->simple_name = MP_QSTR__lt_genexpr_gt_;
Damien429d7192013-10-04 19:53:11 +010040 break;
41 default:
42 assert(0);
43 }
Damienb05d7072013-10-05 13:37:10 +010044 scope->unique_code_id = unique_code_id;
Damien6cdd3af2013-10-05 18:08:26 +010045 scope->emit_options = emit_options;
Damien George78035b92014-04-09 12:27:39 +010046 scope->id_info_alloc = 8;
47 scope->id_info = m_new(id_info_t, scope->id_info_alloc);
Damien429d7192013-10-04 19:53:11 +010048
49 return scope;
50}
51
Paul Sokolovskyfd313582014-01-23 23:05:47 +020052void scope_free(scope_t *scope) {
53 m_del(id_info_t, scope->id_info, scope->id_info_alloc);
54 m_del(scope_t, scope, 1);
55}
56
Damien429d7192013-10-04 19:53:11 +010057id_info_t *scope_find_or_add_id(scope_t *scope, qstr qstr, bool *added) {
58 for (int i = 0; i < scope->id_info_len; i++) {
59 if (scope->id_info[i].qstr == qstr) {
60 *added = false;
61 return &scope->id_info[i];
62 }
63 }
64
65 // make sure we have enough memory
66 if (scope->id_info_len >= scope->id_info_alloc) {
Damien732407f2013-12-29 19:33:23 +000067 scope->id_info = m_renew(id_info_t, scope->id_info, scope->id_info_alloc, scope->id_info_alloc * 2);
Damien429d7192013-10-04 19:53:11 +010068 scope->id_info_alloc *= 2;
Damien429d7192013-10-04 19:53:11 +010069 }
70
Damien Georgecbd2f742014-01-19 11:48:48 +000071 // add new id to end of array of all ids; this seems to match CPython
72 // important thing is that function arguments are first, but that is
73 // handled by the compiler because it adds arguments before compiling the body
74 id_info_t *id_info = &scope->id_info[scope->id_info_len++];
Damien429d7192013-10-04 19:53:11 +010075
76 id_info->param = false;
77 id_info->kind = 0;
78 id_info->qstr = qstr;
Damien27fb45e2013-10-20 15:07:49 +010079 id_info->local_num = 0;
Damien429d7192013-10-04 19:53:11 +010080 *added = true;
81 return id_info;
82}
83
84id_info_t *scope_find(scope_t *scope, qstr qstr) {
85 for (int i = 0; i < scope->id_info_len; i++) {
86 if (scope->id_info[i].qstr == qstr) {
87 return &scope->id_info[i];
88 }
89 }
90 return NULL;
91}
92
93id_info_t *scope_find_global(scope_t *scope, qstr qstr) {
94 while (scope->parent != NULL) {
95 scope = scope->parent;
96 }
97 for (int i = 0; i < scope->id_info_len; i++) {
98 if (scope->id_info[i].qstr == qstr) {
99 return &scope->id_info[i];
100 }
101 }
102 return NULL;
103}
104
105id_info_t *scope_find_local_in_parent(scope_t *scope, qstr qstr) {
106 if (scope->parent == NULL) {
107 return NULL;
108 }
109 for (scope_t *s = scope->parent; s->parent != NULL; s = s->parent) {
110 for (int i = 0; i < s->id_info_len; i++) {
111 if (s->id_info[i].qstr == qstr) {
112 return &s->id_info[i];
113 }
114 }
115 }
116 return NULL;
117}
118
119void scope_close_over_in_parents(scope_t *scope, qstr qstr) {
120 assert(scope->parent != NULL); // we should have at least 1 parent
121 for (scope_t *s = scope->parent; s->parent != NULL; s = s->parent) {
122 id_info_t *id = NULL;
123 for (int i = 0; i < s->id_info_len; i++) {
124 if (s->id_info[i].qstr == qstr) {
125 id = &s->id_info[i];
126 break;
127 }
128 }
129 if (id == NULL) {
130 // variable not declared in this scope, so declare it as free and keep searching parents
131 bool added;
132 id = scope_find_or_add_id(s, qstr, &added);
133 assert(added);
134 id->kind = ID_INFO_KIND_FREE;
135 } else {
136 // variable is declared in this scope, so finish
137 switch (id->kind) {
138 case ID_INFO_KIND_LOCAL: id->kind = ID_INFO_KIND_CELL; break; // variable local to this scope, close it over
139 case ID_INFO_KIND_FREE: break; // variable already closed over in a parent scope
140 case ID_INFO_KIND_CELL: break; // variable already closed over in this scope
141 default: assert(0); // TODO
142 }
143 return;
144 }
145 }
146 assert(0); // we should have found the variable in one of the parents
147}
148
Damien415eb6f2013-10-05 12:19:06 +0100149void scope_declare_global(scope_t *scope, qstr qstr) {
150 if (scope->kind == SCOPE_MODULE) {
151 printf("SyntaxError?: can't declare global in outer code\n");
152 return;
153 }
154 bool added;
155 id_info_t *id_info = scope_find_or_add_id(scope, qstr, &added);
156 if (!added) {
157 printf("SyntaxError?: identifier already declared something\n");
158 return;
159 }
160 id_info->kind = ID_INFO_KIND_GLOBAL_EXPLICIT;
161
162 // if the id exists in the global scope, set its kind to EXPLICIT_GLOBAL
163 id_info = scope_find_global(scope, qstr);
164 if (id_info != NULL) {
165 id_info->kind = ID_INFO_KIND_GLOBAL_EXPLICIT;
166 }
167}
168
169void scope_declare_nonlocal(scope_t *scope, qstr qstr) {
170 if (scope->kind == SCOPE_MODULE) {
171 printf("SyntaxError?: can't declare nonlocal in outer code\n");
172 return;
173 }
174 bool added;
175 id_info_t *id_info = scope_find_or_add_id(scope, qstr, &added);
176 if (!added) {
177 printf("SyntaxError?: identifier already declared something\n");
178 return;
179 }
180 id_info_t *id_info2 = scope_find_local_in_parent(scope, qstr);
181 if (id_info2 == NULL || !(id_info2->kind == ID_INFO_KIND_LOCAL || id_info2->kind == ID_INFO_KIND_CELL || id_info2->kind == ID_INFO_KIND_FREE)) {
182 printf("SyntaxError: no binding for nonlocal '%s' found\n", qstr_str(qstr));
183 return;
184 }
185 id_info->kind = ID_INFO_KIND_FREE;
186 scope_close_over_in_parents(scope, qstr);
187}
188
Damien Georgecbd2f742014-01-19 11:48:48 +0000189#if MICROPY_EMIT_CPYTHON
Damien429d7192013-10-04 19:53:11 +0100190void scope_print_info(scope_t *s) {
191 if (s->kind == SCOPE_MODULE) {
192 printf("code <module>\n");
193 } else if (s->kind == SCOPE_LAMBDA) {
194 printf("code <lambda>\n");
195 } else if (s->kind == SCOPE_LIST_COMP) {
196 printf("code <listcomp>\n");
197 } else if (s->kind == SCOPE_DICT_COMP) {
198 printf("code <dictcomp>\n");
199 } else if (s->kind == SCOPE_SET_COMP) {
200 printf("code <setcomp>\n");
201 } else if (s->kind == SCOPE_GEN_EXPR) {
202 printf("code <genexpr>\n");
203 } else {
204 printf("code %s\n", qstr_str(s->simple_name));
205 }
206 /*
207 printf("var global:");
208 for (int i = 0; i < s->id_info_len; i++) {
209 if (s->id_info[i].kind == ID_INFO_KIND_GLOBAL_EXPLICIT) {
210 printf(" %s", qstr_str(s->id_info[i].qstr));
211 }
212 }
213 printf("\n");
214 printf("var name:");
215 for (int i = 0; i < s->id_info_len; i++) {
216 if (s->id_info[i].kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
217 printf(" %s", qstr_str(s->id_info[i].qstr));
218 }
219 }
220 printf("\n");
221 printf("var local:");
222 for (int i = 0; i < s->id_info_len; i++) {
223 if (s->id_info[i].kind == ID_INFO_KIND_LOCAL) {
224 printf(" %s", qstr_str(s->id_info[i].qstr));
225 }
226 }
227 printf("\n");
228 printf("var free:");
229 for (int i = 0; i < s->id_info_len; i++) {
230 if (s->id_info[i].kind == ID_INFO_KIND_FREE) {
231 printf(" %s", qstr_str(s->id_info[i].qstr));
232 }
233 }
234 printf("\n");
235 */
Damien George8725f8f2014-02-15 19:33:11 +0000236 printf(" flags %04x\n", s->scope_flags);
Damien429d7192013-10-04 19:53:11 +0100237 printf(" argcount %d\n", s->num_params);
238 printf(" nlocals %d\n", s->num_locals);
239 printf(" stacksize %d\n", s->stack_size);
240}
Damien Georgecbd2f742014-01-19 11:48:48 +0000241#endif