1 | /* |
2 | * This file is part of the MicroPython project, http://micropython.org/ |
3 | * |
4 | * The MIT License (MIT) |
5 | * |
6 | * Copyright (c) 2013-2019 Damien P. George |
7 | * Copyright (c) 2014-2015 Paul Sokolovsky |
8 | * |
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | * of this software and associated documentation files (the "Software"), to deal |
11 | * in the Software without restriction, including without limitation the rights |
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
13 | * copies of the Software, and to permit persons to whom the Software is |
14 | * furnished to do so, subject to the following conditions: |
15 | * |
16 | * The above copyright notice and this permission notice shall be included in |
17 | * all copies or substantial portions of the Software. |
18 | * |
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
25 | * THE SOFTWARE. |
26 | */ |
27 | |
28 | #include <stdlib.h> |
29 | #include <string.h> |
30 | #include <assert.h> |
31 | |
32 | #include "py/objmodule.h" |
33 | #include "py/runtime.h" |
34 | #include "py/builtin.h" |
35 | |
36 | #include "genhdr/moduledefs.h" |
37 | |
38 | STATIC void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { |
39 | (void)kind; |
40 | mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in); |
41 | |
42 | const char *module_name = "" ; |
43 | mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_MAP_LOOKUP); |
44 | if (elem != NULL) { |
45 | module_name = mp_obj_str_get_str(elem->value); |
46 | } |
47 | |
48 | #if MICROPY_PY___FILE__ |
49 | // If we store __file__ to imported modules then try to lookup this |
50 | // symbol to give more information about the module. |
51 | elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___file__), MP_MAP_LOOKUP); |
52 | if (elem != NULL) { |
53 | mp_printf(print, "<module '%s' from '%s'>" , module_name, mp_obj_str_get_str(elem->value)); |
54 | return; |
55 | } |
56 | #endif |
57 | |
58 | mp_printf(print, "<module '%s'>" , module_name); |
59 | } |
60 | |
61 | STATIC void module_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { |
62 | mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in); |
63 | if (dest[0] == MP_OBJ_NULL) { |
64 | // load attribute |
65 | mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); |
66 | if (elem != NULL) { |
67 | dest[0] = elem->value; |
68 | #if MICROPY_MODULE_GETATTR |
69 | } else if (attr != MP_QSTR___getattr__) { |
70 | elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___getattr__), MP_MAP_LOOKUP); |
71 | if (elem != NULL) { |
72 | dest[0] = mp_call_function_1(elem->value, MP_OBJ_NEW_QSTR(attr)); |
73 | } |
74 | #endif |
75 | } |
76 | } else { |
77 | // delete/store attribute |
78 | mp_obj_dict_t *dict = self->globals; |
79 | if (dict->map.is_fixed) { |
80 | #if MICROPY_CAN_OVERRIDE_BUILTINS |
81 | if (dict == &mp_module_builtins_globals) { |
82 | if (MP_STATE_VM(mp_module_builtins_override_dict) == NULL) { |
83 | MP_STATE_VM(mp_module_builtins_override_dict) = MP_OBJ_TO_PTR(mp_obj_new_dict(1)); |
84 | } |
85 | dict = MP_STATE_VM(mp_module_builtins_override_dict); |
86 | } else |
87 | #endif |
88 | { |
89 | // can't delete or store to fixed map |
90 | return; |
91 | } |
92 | } |
93 | if (dest[1] == MP_OBJ_NULL) { |
94 | // delete attribute |
95 | mp_obj_dict_delete(MP_OBJ_FROM_PTR(dict), MP_OBJ_NEW_QSTR(attr)); |
96 | } else { |
97 | // store attribute |
98 | mp_obj_dict_store(MP_OBJ_FROM_PTR(dict), MP_OBJ_NEW_QSTR(attr), dest[1]); |
99 | } |
100 | dest[0] = MP_OBJ_NULL; // indicate success |
101 | } |
102 | } |
103 | |
104 | const mp_obj_type_t mp_type_module = { |
105 | { &mp_type_type }, |
106 | .name = MP_QSTR_module, |
107 | .print = module_print, |
108 | .attr = module_attr, |
109 | }; |
110 | |
111 | mp_obj_t mp_obj_new_module(qstr module_name) { |
112 | mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map; |
113 | mp_map_elem_t *el = mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); |
114 | // We could error out if module already exists, but let C extensions |
115 | // add new members to existing modules. |
116 | if (el->value != MP_OBJ_NULL) { |
117 | return el->value; |
118 | } |
119 | |
120 | // create new module object |
121 | mp_obj_module_t *o = m_new_obj(mp_obj_module_t); |
122 | o->base.type = &mp_type_module; |
123 | o->globals = MP_OBJ_TO_PTR(mp_obj_new_dict(MICROPY_MODULE_DICT_SIZE)); |
124 | |
125 | // store __name__ entry in the module |
126 | mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(module_name)); |
127 | |
128 | // store the new module into the slot in the global dict holding all modules |
129 | el->value = MP_OBJ_FROM_PTR(o); |
130 | |
131 | // return the new module |
132 | return MP_OBJ_FROM_PTR(o); |
133 | } |
134 | |
135 | /******************************************************************************/ |
136 | // Global module table and related functions |
137 | |
138 | STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = { |
139 | { MP_ROM_QSTR(MP_QSTR___main__), MP_ROM_PTR(&mp_module___main__) }, |
140 | { MP_ROM_QSTR(MP_QSTR_builtins), MP_ROM_PTR(&mp_module_builtins) }, |
141 | { MP_ROM_QSTR(MP_QSTR_micropython), MP_ROM_PTR(&mp_module_micropython) }, |
142 | |
143 | #if MICROPY_PY_IO |
144 | { MP_ROM_QSTR(MP_QSTR_uio), MP_ROM_PTR(&mp_module_io) }, |
145 | #endif |
146 | #if MICROPY_PY_COLLECTIONS |
147 | { MP_ROM_QSTR(MP_QSTR_ucollections), MP_ROM_PTR(&mp_module_collections) }, |
148 | #endif |
149 | #if MICROPY_PY_STRUCT |
150 | { MP_ROM_QSTR(MP_QSTR_ustruct), MP_ROM_PTR(&mp_module_ustruct) }, |
151 | #endif |
152 | |
153 | #if MICROPY_PY_BUILTINS_FLOAT |
154 | #if MICROPY_PY_MATH |
155 | { MP_ROM_QSTR(MP_QSTR_math), MP_ROM_PTR(&mp_module_math) }, |
156 | #endif |
157 | #if MICROPY_PY_BUILTINS_COMPLEX && MICROPY_PY_CMATH |
158 | { MP_ROM_QSTR(MP_QSTR_cmath), MP_ROM_PTR(&mp_module_cmath) }, |
159 | #endif |
160 | #endif |
161 | #if MICROPY_PY_SYS |
162 | { MP_ROM_QSTR(MP_QSTR_usys), MP_ROM_PTR(&mp_module_sys) }, |
163 | #endif |
164 | #if MICROPY_PY_GC && MICROPY_ENABLE_GC |
165 | { MP_ROM_QSTR(MP_QSTR_gc), MP_ROM_PTR(&mp_module_gc) }, |
166 | #endif |
167 | #if MICROPY_PY_THREAD |
168 | { MP_ROM_QSTR(MP_QSTR__thread), MP_ROM_PTR(&mp_module_thread) }, |
169 | #endif |
170 | |
171 | // extmod modules |
172 | |
173 | #if MICROPY_PY_UASYNCIO |
174 | { MP_ROM_QSTR(MP_QSTR__uasyncio), MP_ROM_PTR(&mp_module_uasyncio) }, |
175 | #endif |
176 | #if MICROPY_PY_UERRNO |
177 | { MP_ROM_QSTR(MP_QSTR_uerrno), MP_ROM_PTR(&mp_module_uerrno) }, |
178 | #endif |
179 | #if MICROPY_PY_UCTYPES |
180 | { MP_ROM_QSTR(MP_QSTR_uctypes), MP_ROM_PTR(&mp_module_uctypes) }, |
181 | #endif |
182 | #if MICROPY_PY_UZLIB |
183 | { MP_ROM_QSTR(MP_QSTR_uzlib), MP_ROM_PTR(&mp_module_uzlib) }, |
184 | #endif |
185 | #if MICROPY_PY_UJSON |
186 | { MP_ROM_QSTR(MP_QSTR_ujson), MP_ROM_PTR(&mp_module_ujson) }, |
187 | #endif |
188 | #if MICROPY_PY_URE |
189 | { MP_ROM_QSTR(MP_QSTR_ure), MP_ROM_PTR(&mp_module_ure) }, |
190 | #endif |
191 | #if MICROPY_PY_UHEAPQ |
192 | { MP_ROM_QSTR(MP_QSTR_uheapq), MP_ROM_PTR(&mp_module_uheapq) }, |
193 | #endif |
194 | #if MICROPY_PY_UTIMEQ |
195 | { MP_ROM_QSTR(MP_QSTR_utimeq), MP_ROM_PTR(&mp_module_utimeq) }, |
196 | #endif |
197 | #if MICROPY_PY_UHASHLIB |
198 | { MP_ROM_QSTR(MP_QSTR_uhashlib), MP_ROM_PTR(&mp_module_uhashlib) }, |
199 | #endif |
200 | #if MICROPY_PY_UCRYPTOLIB |
201 | { MP_ROM_QSTR(MP_QSTR_ucryptolib), MP_ROM_PTR(&mp_module_ucryptolib) }, |
202 | #endif |
203 | #if MICROPY_PY_UBINASCII |
204 | { MP_ROM_QSTR(MP_QSTR_ubinascii), MP_ROM_PTR(&mp_module_ubinascii) }, |
205 | #endif |
206 | #if MICROPY_PY_URANDOM |
207 | { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&mp_module_urandom) }, |
208 | #endif |
209 | #if MICROPY_PY_USELECT |
210 | { MP_ROM_QSTR(MP_QSTR_uselect), MP_ROM_PTR(&mp_module_uselect) }, |
211 | #endif |
212 | #if MICROPY_PY_USSL |
213 | { MP_ROM_QSTR(MP_QSTR_ussl), MP_ROM_PTR(&mp_module_ussl) }, |
214 | #endif |
215 | #if MICROPY_PY_LWIP |
216 | { MP_ROM_QSTR(MP_QSTR_lwip), MP_ROM_PTR(&mp_module_lwip) }, |
217 | #endif |
218 | #if MICROPY_PY_UWEBSOCKET |
219 | { MP_ROM_QSTR(MP_QSTR_uwebsocket), MP_ROM_PTR(&mp_module_uwebsocket) }, |
220 | #endif |
221 | #if MICROPY_PY_WEBREPL |
222 | { MP_ROM_QSTR(MP_QSTR__webrepl), MP_ROM_PTR(&mp_module_webrepl) }, |
223 | #endif |
224 | #if MICROPY_PY_FRAMEBUF |
225 | { MP_ROM_QSTR(MP_QSTR_framebuf), MP_ROM_PTR(&mp_module_framebuf) }, |
226 | #endif |
227 | #if MICROPY_PY_BTREE |
228 | { MP_ROM_QSTR(MP_QSTR_btree), MP_ROM_PTR(&mp_module_btree) }, |
229 | #endif |
230 | #if MICROPY_PY_BLUETOOTH |
231 | { MP_ROM_QSTR(MP_QSTR_ubluetooth), MP_ROM_PTR(&mp_module_ubluetooth) }, |
232 | #endif |
233 | |
234 | // extra builtin modules as defined by a port |
235 | MICROPY_PORT_BUILTIN_MODULES |
236 | |
237 | #ifdef MICROPY_REGISTERED_MODULES |
238 | // builtin modules declared with MP_REGISTER_MODULE() |
239 | MICROPY_REGISTERED_MODULES |
240 | #endif |
241 | }; |
242 | |
243 | MP_DEFINE_CONST_MAP(mp_builtin_module_map, mp_builtin_module_table); |
244 | |
245 | // returns MP_OBJ_NULL if not found |
246 | mp_obj_t mp_module_get(qstr module_name) { |
247 | mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map; |
248 | // lookup module |
249 | mp_map_elem_t *el = mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP); |
250 | |
251 | if (el == NULL) { |
252 | // module not found, look for builtin module names |
253 | el = mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP); |
254 | if (el == NULL) { |
255 | return MP_OBJ_NULL; |
256 | } |
257 | mp_module_call_init(module_name, el->value); |
258 | } |
259 | |
260 | // module found, return it |
261 | return el->value; |
262 | } |
263 | |
264 | void mp_module_register(qstr qst, mp_obj_t module) { |
265 | mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map; |
266 | mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module; |
267 | } |
268 | |
269 | #if MICROPY_MODULE_WEAK_LINKS |
270 | // Search for u"foo" in built-in modules, return MP_OBJ_NULL if not found |
271 | mp_obj_t mp_module_search_umodule(const char *module_str) { |
272 | for (size_t i = 0; i < MP_ARRAY_SIZE(mp_builtin_module_table); ++i) { |
273 | const mp_map_elem_t *entry = (const mp_map_elem_t *)&mp_builtin_module_table[i]; |
274 | const char *key = qstr_str(MP_OBJ_QSTR_VALUE(entry->key)); |
275 | if (key[0] == 'u' && strcmp(&key[1], module_str) == 0) { |
276 | return (mp_obj_t)entry->value; |
277 | } |
278 | |
279 | } |
280 | return MP_OBJ_NULL; |
281 | } |
282 | #endif |
283 | |
284 | #if MICROPY_MODULE_BUILTIN_INIT |
285 | void mp_module_call_init(qstr module_name, mp_obj_t module_obj) { |
286 | // Look for __init__ and call it if it exists |
287 | mp_obj_t dest[2]; |
288 | mp_load_method_maybe(module_obj, MP_QSTR___init__, dest); |
289 | if (dest[0] != MP_OBJ_NULL) { |
290 | mp_call_method_n_kw(0, 0, dest); |
291 | // Register module so __init__ is not called again. |
292 | // If a module can be referenced by more than one name (eg due to weak links) |
293 | // then __init__ will still be called for each distinct import, and it's then |
294 | // up to the particular module to make sure it's __init__ code only runs once. |
295 | mp_module_register(module_name, module_obj); |
296 | } |
297 | } |
298 | #endif |
299 | |