Branch data Line data Source code
1 : : /*
2 : : * This file is part of the MicroPython project, http://micropython.org/
3 : : *
4 : : * The MIT License (MIT)
5 : : *
6 : : * Copyright (c) 2013, 2014 Damien P. George
7 : : *
8 : : * Permission is hereby granted, free of charge, to any person obtaining a copy
9 : : * of this software and associated documentation files (the "Software"), to deal
10 : : * in the Software without restriction, including without limitation the rights
11 : : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : : * copies of the Software, and to permit persons to whom the Software is
13 : : * furnished to do so, subject to the following conditions:
14 : : *
15 : : * The above copyright notice and this permission notice shall be included in
16 : : * all copies or substantial portions of the Software.
17 : : *
18 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 : : * THE SOFTWARE.
25 : : */
26 : :
27 : : #include <assert.h>
28 : :
29 : : #include "py/scope.h"
30 : :
31 : : #if MICROPY_ENABLE_COMPILER
32 : :
33 : : // These low numbered qstrs should fit in 8 bits. See assertions below.
34 : : // The (unescaped) names appear in `unsorted_str_list` in the QSTR
35 : : // generator script py/makeqstrdata.py to ensure they are assigned low numbers.
36 : : static const uint8_t scope_simple_name_table[] = {
37 : : [SCOPE_MODULE] = MP_QSTR__lt_module_gt_,
38 : : [SCOPE_LAMBDA] = MP_QSTR__lt_lambda_gt_,
39 : : [SCOPE_LIST_COMP] = MP_QSTR__lt_listcomp_gt_,
40 : : [SCOPE_DICT_COMP] = MP_QSTR__lt_dictcomp_gt_,
41 : : [SCOPE_SET_COMP] = MP_QSTR__lt_setcomp_gt_,
42 : : [SCOPE_GEN_EXPR] = MP_QSTR__lt_genexpr_gt_,
43 : : };
44 : :
45 : 10289 : scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, mp_uint_t emit_options) {
46 : : // Make sure those qstrs indeed fit in an uint8_t.
47 : 10289 : MP_STATIC_ASSERT(MP_QSTR__lt_module_gt_ <= UINT8_MAX);
48 : 10289 : MP_STATIC_ASSERT(MP_QSTR__lt_lambda_gt_ <= UINT8_MAX);
49 : 10289 : MP_STATIC_ASSERT(MP_QSTR__lt_listcomp_gt_ <= UINT8_MAX);
50 : 10289 : MP_STATIC_ASSERT(MP_QSTR__lt_dictcomp_gt_ <= UINT8_MAX);
51 : 10289 : MP_STATIC_ASSERT(MP_QSTR__lt_setcomp_gt_ <= UINT8_MAX);
52 : 10289 : MP_STATIC_ASSERT(MP_QSTR__lt_genexpr_gt_ <= UINT8_MAX);
53 : :
54 : 10289 : scope_t *scope = m_new0(scope_t, 1);
55 : 10289 : scope->kind = kind;
56 : 10289 : scope->pn = pn;
57 [ + + ]: 10289 : if (kind == SCOPE_FUNCTION || kind == SCOPE_CLASS) {
58 [ + - - + ]: 6032 : assert(MP_PARSE_NODE_IS_STRUCT(pn));
59 : 6032 : scope->simple_name = MP_PARSE_NODE_LEAF_ARG(((mp_parse_node_struct_t *)pn)->nodes[0]);
60 : : } else {
61 : 4257 : scope->simple_name = scope_simple_name_table[kind];
62 : : }
63 : 10289 : scope->raw_code = mp_emit_glue_new_raw_code();
64 : 10289 : scope->emit_options = emit_options;
65 : 10289 : scope->id_info_alloc = MICROPY_ALLOC_SCOPE_ID_INIT;
66 : 10289 : scope->id_info = m_new(id_info_t, scope->id_info_alloc);
67 : :
68 : 10288 : return scope;
69 : : }
70 : :
71 : 10251 : void scope_free(scope_t *scope) {
72 : 10251 : m_del(id_info_t, scope->id_info, scope->id_info_alloc);
73 : 10251 : m_del(scope_t, scope, 1);
74 : 10251 : }
75 : :
76 : 114169 : id_info_t *scope_find_or_add_id(scope_t *scope, qstr qst, id_info_kind_t kind) {
77 : 114169 : id_info_t *id_info = scope_find(scope, qst);
78 [ + + ]: 114169 : if (id_info != NULL) {
79 : : return id_info;
80 : : }
81 : :
82 : : // make sure we have enough memory
83 [ + + ]: 42066 : if (scope->id_info_len >= scope->id_info_alloc) {
84 : 4251 : scope->id_info = m_renew(id_info_t, scope->id_info, scope->id_info_alloc, scope->id_info_alloc + MICROPY_ALLOC_SCOPE_ID_INC);
85 : 4251 : scope->id_info_alloc += MICROPY_ALLOC_SCOPE_ID_INC;
86 : : }
87 : :
88 : : // add new id to end of array of all ids; this seems to match CPython
89 : : // important thing is that function arguments are first, but that is
90 : : // handled by the compiler because it adds arguments before compiling the body
91 : 42066 : id_info = &scope->id_info[scope->id_info_len++];
92 : :
93 : 42066 : id_info->kind = kind;
94 : 42066 : id_info->flags = 0;
95 : 42066 : id_info->local_num = 0;
96 : 42066 : id_info->qst = qst;
97 : 42066 : return id_info;
98 : : }
99 : :
100 : 560740 : id_info_t *scope_find(scope_t *scope, qstr qst) {
101 [ + + ]: 2507346 : for (mp_uint_t i = 0; i < scope->id_info_len; i++) {
102 [ + + ]: 2462642 : if (scope->id_info[i].qst == qst) {
103 : : return &scope->id_info[i];
104 : : }
105 : : }
106 : : return NULL;
107 : : }
108 : :
109 : 379 : id_info_t *scope_find_global(scope_t *scope, qstr qst) {
110 [ + + ]: 884 : while (scope->parent != NULL) {
111 : : scope = scope->parent;
112 : : }
113 : 379 : return scope_find(scope, qst);
114 : : }
115 : :
116 : 239 : static void scope_close_over_in_parents(scope_t *scope, qstr qst) {
117 [ - + ]: 239 : assert(scope->parent != NULL); // we should have at least 1 parent
118 : 13 : for (scope_t *s = scope->parent;; s = s->parent) {
119 [ - + ]: 252 : assert(s->parent != NULL); // we should not get to the outer scope
120 : 252 : id_info_t *id = scope_find_or_add_id(s, qst, ID_INFO_KIND_UNDECIDED);
121 [ + + ]: 252 : if (id->kind == ID_INFO_KIND_UNDECIDED) {
122 : : // variable not previously declared in this scope, so declare it as free and keep searching parents
123 : 13 : id->kind = ID_INFO_KIND_FREE;
124 : : } else {
125 : : // variable is declared in this scope, so finish
126 [ + + ]: 239 : if (id->kind == ID_INFO_KIND_LOCAL) {
127 : : // variable local to this scope, close it over
128 : 209 : id->kind = ID_INFO_KIND_CELL;
129 : : } else {
130 : : // ID_INFO_KIND_FREE: variable already closed over in a parent scope
131 : : // ID_INFO_KIND_CELL: variable already closed over in this scope
132 [ - + ]: 30 : assert(id->kind == ID_INFO_KIND_FREE || id->kind == ID_INFO_KIND_CELL);
133 : : }
134 : 239 : return;
135 : : }
136 : : }
137 : : }
138 : :
139 : 17081 : void scope_check_to_close_over(scope_t *scope, id_info_t *id) {
140 [ + + ]: 17081 : if (scope->parent != NULL) {
141 [ + + ]: 11526 : for (scope_t *s = scope->parent; s->parent != NULL; s = s->parent) {
142 : 3020 : id_info_t *id2 = scope_find(s, id->qst);
143 [ + + ]: 3021 : if (id2 != NULL) {
144 [ + + ]: 524 : if (id2->kind == ID_INFO_KIND_LOCAL || id2->kind == ID_INFO_KIND_CELL || id2->kind == ID_INFO_KIND_FREE) {
145 : 239 : id->kind = ID_INFO_KIND_FREE;
146 : 239 : scope_close_over_in_parents(scope, id->qst);
147 : : }
148 : : break;
149 : : }
150 : : }
151 : : }
152 : 17082 : }
153 : :
154 : : #endif // MICROPY_ENABLE_COMPILER
|