blob: ae24646295e7401a49991b02a6ee4349031842fe [file] [log] [blame]
Damien429d7192013-10-04 19:53:11 +01001#include <stdint.h>
2#include <stdlib.h>
3#include <stdio.h>
4#include <string.h>
5#include <assert.h>
6
7#include "misc.h"
Damienc025ebb2013-10-12 14:30:21 +01008#include "mpyconfig.h"
Damien429d7192013-10-04 19:53:11 +01009#include "runtime.h"
Damieneb19efb2013-10-10 22:06:54 +010010#include "bc.h"
Damien429d7192013-10-04 19:53:11 +010011
Damien7f5dacf2013-10-10 11:24:39 +010012#if 0 // print debugging info
Damiena1ddfcc2013-10-10 23:25:50 +010013#define DEBUG_PRINT (1)
14#define WRITE_NATIVE (1)
Damien7f5dacf2013-10-10 11:24:39 +010015#define DEBUG_printf(args...) printf(args)
16#define DEBUG_OP_printf(args...) printf(args)
17#else // don't print debugging info
Damiena3977762013-10-09 23:10:10 +010018#define DEBUG_printf(args...) (void)0
Damien429d7192013-10-04 19:53:11 +010019#define DEBUG_OP_printf(args...) (void)0
Damien7f5dacf2013-10-10 11:24:39 +010020#endif
Damien429d7192013-10-04 19:53:11 +010021
Damien429d7192013-10-04 19:53:11 +010022typedef machine_int_t py_small_int_t;
23
24#define IS_O(o, k) (((((py_small_int_t)(o)) & 1) == 0) && (((py_obj_base_t*)(o))->kind == (k)))
25#define IS_SMALL_INT(o) (((py_small_int_t)(o)) & 1)
26#define FROM_SMALL_INT(o) (((py_small_int_t)(o)) >> 1)
27#define TO_SMALL_INT(o) ((py_obj_t)(((o) << 1) | 1))
28
Damienc025ebb2013-10-12 14:30:21 +010029#ifdef MICROPY_ENABLE_FLOAT
Damien429d7192013-10-04 19:53:11 +010030typedef machine_float_t float_t;
31#endif
32
33typedef enum {
34 O_CONST,
35 O_STR,
Damienc025ebb2013-10-12 14:30:21 +010036#ifdef MICROPY_ENABLE_FLOAT
Damien429d7192013-10-04 19:53:11 +010037 O_FLOAT,
38#endif
39 O_FUN_0,
40 O_FUN_1,
41 O_FUN_2,
42 O_FUN_N,
43 O_FUN_BC,
Damien826005c2013-10-05 23:17:28 +010044 O_FUN_ASM,
Damien429d7192013-10-04 19:53:11 +010045 O_BOUND_METH,
46 O_LIST,
47 O_SET,
48 O_MAP,
49 O_CLASS,
Damiena3977762013-10-09 23:10:10 +010050 O_OBJ,
Damien429d7192013-10-04 19:53:11 +010051} py_obj_kind_t;
52
53typedef enum {
54 MAP_QSTR,
55 MAP_PY_OBJ,
56} py_map_kind_t;
57
58typedef struct _py_map_elem_t {
59 py_obj_t key;
60 py_obj_t value;
61} py_map_elem_t;
62
63typedef struct _py_map_t {
Damiena3977762013-10-09 23:10:10 +010064 py_map_kind_t kind; // TODO merge this 1-bit field into alloc or used
Damien429d7192013-10-04 19:53:11 +010065 machine_uint_t alloc;
66 machine_uint_t used;
67 py_map_elem_t *table;
68} py_map_t;
69
Damiena3977762013-10-09 23:10:10 +010070typedef struct _py_obj_base_t py_obj_base_t;
71
72struct _py_obj_base_t {
Damien429d7192013-10-04 19:53:11 +010073 py_obj_kind_t kind;
74 union {
75 const char *id;
76 qstr u_str;
Damienc025ebb2013-10-12 14:30:21 +010077#ifdef MICROPY_ENABLE_FLOAT
Damiene4af64f2013-10-06 12:04:13 +010078 float_t u_flt;
Damien429d7192013-10-04 19:53:11 +010079#endif
80 struct { // for O_FUN_[012N]
Damien429d7192013-10-04 19:53:11 +010081 int n_args;
Damien826005c2013-10-05 23:17:28 +010082 void *fun;
Damien429d7192013-10-04 19:53:11 +010083 } u_fun;
84 struct { // for O_FUN_BC
Damien826005c2013-10-05 23:17:28 +010085 int n_args;
Damien429d7192013-10-04 19:53:11 +010086 byte *code;
87 uint len;
Damien429d7192013-10-04 19:53:11 +010088 } u_fun_bc;
Damien826005c2013-10-05 23:17:28 +010089 struct { // for O_FUN_ASM
90 int n_args;
91 void *fun;
92 } u_fun_asm;
Damien429d7192013-10-04 19:53:11 +010093 struct { // for O_BOUND_METH
94 py_obj_t meth;
95 py_obj_t self;
96 } u_bound_meth;
97 struct { // for O_LIST
98 int alloc;
99 int len;
100 py_obj_t *items;
101 } u_list;
102 struct { // for O_SET
103 int alloc;
104 int used;
105 py_obj_t *table;
106 } u_set;
107 py_map_t u_map; // for O_MAP
Damien429d7192013-10-04 19:53:11 +0100108 struct { // for O_CLASS
Damiena3977762013-10-09 23:10:10 +0100109 py_map_t *locals;
Damien429d7192013-10-04 19:53:11 +0100110 } u_class;
Damiena3977762013-10-09 23:10:10 +0100111 struct { // for O_OBJ
112 py_obj_base_t *class; // points to a O_CLASS object
113 py_map_t *members;
114 } u_obj;
Damien429d7192013-10-04 19:53:11 +0100115 };
Damiena3977762013-10-09 23:10:10 +0100116};
Damien429d7192013-10-04 19:53:11 +0100117
118py_obj_t py_const_none;
119py_obj_t py_const_false;
120py_obj_t py_const_true;
121
Damieneb19efb2013-10-10 22:06:54 +0100122// locals and globals need to be pointers because they can be the same in outer module scope
123py_map_t *map_locals;
124py_map_t *map_globals;
Damien429d7192013-10-04 19:53:11 +0100125py_map_t map_builtins;
126
127// approximatelly doubling primes; made with Mathematica command: Table[Prime[Floor[(1.7)^n]], {n, 3, 24}]
128static int doubling_primes[] = {7, 19, 43, 89, 179, 347, 647, 1229, 2297, 4243, 7829, 14347, 26017, 47149, 84947, 152443, 273253, 488399, 869927, 1547173, 2745121, 4861607};
129
130int get_doubling_prime_greater_or_equal_to(int x) {
131 for (int i = 0; i < sizeof(doubling_primes) / sizeof(int); i++) {
132 if (doubling_primes[i] >= x) {
133 return doubling_primes[i];
134 }
135 }
136 // ran out of primes in the table!
137 // return something sensible, at least make it odd
138 return x | 1;
139}
140
141void py_map_init(py_map_t *map, py_map_kind_t kind, int n) {
142 map->kind = kind;
143 map->alloc = get_doubling_prime_greater_or_equal_to(n + 1);
144 map->used = 0;
145 map->table = m_new(py_map_elem_t, map->alloc);
146 for (int i = 0; i < map->alloc; i++) {
147 map->table[i].key = NULL;
148 map->table[i].value = NULL;
149 }
150}
151
152py_map_t *py_map_new(py_map_kind_t kind, int n) {
153 py_map_t *map = m_new(py_map_t, 1);
154 py_map_init(map, kind, n);
155 return map;
156}
157
158int py_obj_hash(py_obj_t o_in) {
159 if (IS_SMALL_INT(o_in)) {
160 return FROM_SMALL_INT(o_in);
161 } else if (IS_O(o_in, O_STR)) {
162 return ((py_obj_base_t*)o_in)->u_str;
163 } else {
164 assert(0);
165 return 0;
166 }
167}
168
169bool py_obj_equal(py_obj_t o1, py_obj_t o2) {
170 if (o1 == o2) {
171 return true;
172 } else if (IS_SMALL_INT(o1) && IS_SMALL_INT(o2)) {
173 return false;
174 } else if (IS_O(o1, O_STR) && IS_O(o2, O_STR)) {
175 return ((py_obj_base_t*)o1)->u_str == ((py_obj_base_t*)o2)->u_str;
176 } else {
177 assert(0);
178 return false;
179 }
180}
181
182py_map_elem_t* py_map_lookup_helper(py_map_t *map, py_obj_t index, bool add_if_not_found) {
183 bool is_map_py_obj = (map->kind == MAP_PY_OBJ);
184 machine_uint_t hash;
185 if (is_map_py_obj) {
186 hash = py_obj_hash(index);
187 } else {
188 hash = (machine_uint_t)index;
189 }
190 uint pos = hash % map->alloc;
191 for (;;) {
192 py_map_elem_t *elem = &map->table[pos];
193 if (elem->key == NULL) {
194 // not in table
195 if (add_if_not_found) {
196 if (map->used + 1 >= map->alloc) {
197 // not enough room in table, rehash it
198 int old_alloc = map->alloc;
199 py_map_elem_t *old_table = map->table;
200 map->alloc = get_doubling_prime_greater_or_equal_to(map->alloc + 1);
201 map->used = 0;
202 map->table = m_new(py_map_elem_t, map->alloc);
203 for (int i = 0; i < old_alloc; i++) {
204 if (old_table[i].key != NULL) {
205 py_map_lookup_helper(map, old_table[i].key, true)->value = old_table[i].value;
206 }
207 }
208 m_free(old_table);
209 // restart the search for the new element
210 pos = hash % map->alloc;
211 } else {
212 map->used += 1;
213 elem->key = index;
214 return elem;
215 }
216 } else {
217 return NULL;
218 }
219 } else if (elem->key == index || (is_map_py_obj && py_obj_equal(elem->key, index))) {
220 // found it
221 if (add_if_not_found) {
222 elem->key = index;
223 }
224 return elem;
225 } else {
226 // not yet found, keep searching in this table
227 pos = (pos + 1) % map->alloc;
228 }
229 }
230}
231
232py_map_elem_t* py_qstr_map_lookup(py_map_t *map, qstr index, bool add_if_not_found) {
233 py_obj_t o = (py_obj_t)(machine_uint_t)index;
234 return py_map_lookup_helper(map, o, add_if_not_found);
235}
236
237py_map_elem_t* py_map_lookup(py_obj_t o, py_obj_t index, bool add_if_not_found) {
238 assert(IS_O(o, O_MAP));
239 return py_map_lookup_helper(&((py_obj_base_t *)o)->u_map, index, add_if_not_found);
240}
241
242static bool fit_small_int(py_small_int_t o) {
243 return true;
244}
245
246py_obj_t py_obj_new_const(const char *id) {
247 py_obj_base_t *o = m_new(py_obj_base_t, 1);
248 o->kind = O_CONST;
249 o->id = id;
250 return (py_obj_t)o;
251}
252
253py_obj_t py_obj_new_str(qstr qstr) {
254 py_obj_base_t *o = m_new(py_obj_base_t, 1);
255 o->kind = O_STR;
256 o->u_str = qstr;
257 return (py_obj_t)o;
258}
259
Damienc025ebb2013-10-12 14:30:21 +0100260#ifdef MICROPY_ENABLE_FLOAT
Damien429d7192013-10-04 19:53:11 +0100261py_obj_t py_obj_new_float(float_t val) {
262 py_obj_base_t *o = m_new(py_obj_base_t, 1);
263 o->kind = O_FLOAT;
Damiene4af64f2013-10-06 12:04:13 +0100264 o->u_flt = val;
Damien429d7192013-10-04 19:53:11 +0100265 return (py_obj_t)o;
266}
267#endif
268
269py_obj_t list_append(py_obj_t self_in, py_obj_t arg) {
270 assert(IS_O(self_in, O_LIST));
271 py_obj_base_t *self = self_in;
272 if (self->u_list.len >= self->u_list.alloc) {
273 self->u_list.alloc *= 2;
274 self->u_list.items = m_renew(py_obj_t, self->u_list.items, self->u_list.alloc);
275 }
276 self->u_list.items[self->u_list.len++] = arg;
277 return arg;
278}
279
280static qstr q_append;
281static qstr q_print;
282static qstr q_len;
283static qstr q___build_class__;
284
285typedef enum {
Damien826005c2013-10-05 23:17:28 +0100286 PY_CODE_NONE,
Damien429d7192013-10-04 19:53:11 +0100287 PY_CODE_BYTE,
Damien826005c2013-10-05 23:17:28 +0100288 PY_CODE_NATIVE,
289 PY_CODE_INLINE_ASM,
Damien429d7192013-10-04 19:53:11 +0100290} py_code_kind_t;
291
292typedef struct _py_code_t {
293 py_code_kind_t kind;
294 int n_args;
295 union {
296 struct {
Damien429d7192013-10-04 19:53:11 +0100297 byte *code;
298 uint len;
299 } u_byte;
Damien826005c2013-10-05 23:17:28 +0100300 struct {
301 py_fun_t fun;
302 } u_native;
303 struct {
Damiene4af64f2013-10-06 12:04:13 +0100304 void *fun;
Damien826005c2013-10-05 23:17:28 +0100305 } u_inline_asm;
Damien429d7192013-10-04 19:53:11 +0100306 };
307} py_code_t;
308
309static int next_unique_code_id;
310static py_code_t *unique_codes;
311
312py_obj_t fun_list_append;
313
314py_obj_t py_builtin_print(py_obj_t o) {
315 if (IS_O(o, O_STR)) {
316 // special case, print string raw
317 printf("%s\n", qstr_str(((py_obj_base_t*)o)->u_str));
318 } else {
319 // print the object Python style
320 py_obj_print(o);
321 printf("\n");
322 }
323 return py_const_none;
324}
325
326py_obj_t py_builtin_len(py_obj_t o_in) {
327 py_small_int_t len = 0;
328 if (IS_O(o_in, O_LIST)) {
329 py_obj_base_t *o = o_in;
330 len = o->u_list.len;
331 } else if (IS_O(o_in, O_MAP)) {
332 py_obj_base_t *o = o_in;
333 len = o->u_map.used;
334 } else {
335 assert(0);
336 }
337 return TO_SMALL_INT(len);
338}
339
Damiena3977762013-10-09 23:10:10 +0100340py_obj_t py_builtin___build_class__(py_obj_t o_class_fun, py_obj_t o_class_name) {
341 // we differ from CPython: we set the new __locals__ object here
Damieneb19efb2013-10-10 22:06:54 +0100342 py_map_t *old_locals = map_locals;
Damiena3977762013-10-09 23:10:10 +0100343 py_map_t *class_locals = py_map_new(MAP_QSTR, 0);
Damieneb19efb2013-10-10 22:06:54 +0100344 map_locals = class_locals;
Damiena3977762013-10-09 23:10:10 +0100345
346 // call the class code
347 rt_call_function_1(o_class_fun, (py_obj_t)0xdeadbeef);
348
349 // restore old __locals__ object
350 map_locals = old_locals;
351
352 // create and return the new class
Damien429d7192013-10-04 19:53:11 +0100353 py_obj_base_t *o = m_new(py_obj_base_t, 1);
354 o->kind = O_CLASS;
Damiena3977762013-10-09 23:10:10 +0100355 o->u_class.locals = class_locals;
Damien429d7192013-10-04 19:53:11 +0100356 return o;
357}
358
Damiena1ddfcc2013-10-10 23:25:50 +0100359#ifdef WRITE_NATIVE
Damien429d7192013-10-04 19:53:11 +0100360FILE *fp_native = NULL;
Damiena1ddfcc2013-10-10 23:25:50 +0100361#endif
Damien429d7192013-10-04 19:53:11 +0100362
363void rt_init() {
364 q_append = qstr_from_str_static("append");
365 q_print = qstr_from_str_static("print");
366 q_len = qstr_from_str_static("len");
367 q___build_class__ = qstr_from_str_static("__build_class__");
368
369 py_const_none = py_obj_new_const("None");
370 py_const_false = py_obj_new_const("False");
371 py_const_true = py_obj_new_const("True");
372
Damieneb19efb2013-10-10 22:06:54 +0100373 // locals = globals for outer module (see Objects/frameobject.c/PyFrame_New())
374 map_locals = map_globals = py_map_new(MAP_QSTR, 1);
375 py_qstr_map_lookup(map_globals, qstr_from_str_static("__name__"), true)->value = py_obj_new_str(qstr_from_str_static("__main__"));
Damien429d7192013-10-04 19:53:11 +0100376
377 py_map_init(&map_builtins, MAP_QSTR, 3);
378 py_qstr_map_lookup(&map_builtins, q_print, true)->value = rt_make_function_1(py_builtin_print);
379 py_qstr_map_lookup(&map_builtins, q_len, true)->value = rt_make_function_1(py_builtin_len);
380 py_qstr_map_lookup(&map_builtins, q___build_class__, true)->value = rt_make_function_2(py_builtin___build_class__);
381
382 next_unique_code_id = 1;
383 unique_codes = NULL;
384
385 fun_list_append = rt_make_function_2(list_append);
386
Damiena1ddfcc2013-10-10 23:25:50 +0100387#ifdef WRITE_NATIVE
Damien429d7192013-10-04 19:53:11 +0100388 fp_native = fopen("out-native", "wb");
Damiena1ddfcc2013-10-10 23:25:50 +0100389#endif
Damien429d7192013-10-04 19:53:11 +0100390}
391
392void rt_deinit() {
Damiena1ddfcc2013-10-10 23:25:50 +0100393#ifdef WRITE_NATIVE
Damien429d7192013-10-04 19:53:11 +0100394 if (fp_native != NULL) {
395 fclose(fp_native);
396 }
Damiena1ddfcc2013-10-10 23:25:50 +0100397#endif
Damien429d7192013-10-04 19:53:11 +0100398}
399
400int rt_get_new_unique_code_id() {
401 return next_unique_code_id++;
402}
403
Damien826005c2013-10-05 23:17:28 +0100404static void alloc_unique_codes() {
Damien429d7192013-10-04 19:53:11 +0100405 if (unique_codes == NULL) {
406 unique_codes = m_new(py_code_t, next_unique_code_id);
Damien826005c2013-10-05 23:17:28 +0100407 for (int i = 0; i < next_unique_code_id; i++) {
408 unique_codes[i].kind = PY_CODE_NONE;
409 }
Damien429d7192013-10-04 19:53:11 +0100410 }
Damien826005c2013-10-05 23:17:28 +0100411}
412
413void rt_assign_byte_code(int unique_code_id, byte *code, uint len, int n_args) {
414 alloc_unique_codes();
415
416 assert(unique_code_id < next_unique_code_id);
417 unique_codes[unique_code_id].kind = PY_CODE_BYTE;
418 unique_codes[unique_code_id].n_args = n_args;
419 unique_codes[unique_code_id].u_byte.code = code;
420 unique_codes[unique_code_id].u_byte.len = len;
421
422 DEBUG_printf("assign byte code: id=%d code=%p len=%u n_args=%d\n", unique_code_id, code, len, n_args);
423}
424
425void rt_assign_native_code(int unique_code_id, py_fun_t fun, uint len, int n_args) {
426 alloc_unique_codes();
427
Damienb05d7072013-10-05 13:37:10 +0100428 assert(1 <= unique_code_id && unique_code_id < next_unique_code_id);
Damien429d7192013-10-04 19:53:11 +0100429 unique_codes[unique_code_id].kind = PY_CODE_NATIVE;
430 unique_codes[unique_code_id].n_args = n_args;
431 unique_codes[unique_code_id].u_native.fun = fun;
432
Damiena1ddfcc2013-10-10 23:25:50 +0100433#ifdef DEBUG_PRINT
Damien429d7192013-10-04 19:53:11 +0100434 DEBUG_printf("assign native code: id=%d fun=%p len=%u n_args=%d\n", unique_code_id, fun, len, n_args);
435 byte *fun_data = (byte*)(((machine_uint_t)fun) & (~1)); // need to clear lower bit in case it's thumb code
436 for (int i = 0; i < 128 && i < len; i++) {
437 if (i > 0 && i % 16 == 0) {
438 DEBUG_printf("\n");
439 }
440 DEBUG_printf(" %02x", fun_data[i]);
441 }
442 DEBUG_printf("\n");
443
Damiena1ddfcc2013-10-10 23:25:50 +0100444#ifdef WRITE_NATIVE
Damien429d7192013-10-04 19:53:11 +0100445 if (fp_native != NULL) {
446 fwrite(fun_data, len, 1, fp_native);
Damien13ed3a62013-10-08 09:05:10 +0100447 fflush(fp_native);
Damien429d7192013-10-04 19:53:11 +0100448 }
Damiena1ddfcc2013-10-10 23:25:50 +0100449#endif
450#endif
Damien429d7192013-10-04 19:53:11 +0100451}
452
Damien826005c2013-10-05 23:17:28 +0100453void rt_assign_inline_asm_code(int unique_code_id, py_fun_t fun, uint len, int n_args) {
454 alloc_unique_codes();
Damien429d7192013-10-04 19:53:11 +0100455
Damien826005c2013-10-05 23:17:28 +0100456 assert(1 <= unique_code_id && unique_code_id < next_unique_code_id);
457 unique_codes[unique_code_id].kind = PY_CODE_INLINE_ASM;
458 unique_codes[unique_code_id].n_args = n_args;
459 unique_codes[unique_code_id].u_inline_asm.fun = fun;
460
Damiena1ddfcc2013-10-10 23:25:50 +0100461#ifdef DEBUG_PRINT
Damien826005c2013-10-05 23:17:28 +0100462 DEBUG_printf("assign inline asm code: id=%d fun=%p len=%u n_args=%d\n", unique_code_id, fun, len, n_args);
463 byte *fun_data = (byte*)(((machine_uint_t)fun) & (~1)); // need to clear lower bit in case it's thumb code
464 for (int i = 0; i < 128 && i < len; i++) {
465 if (i > 0 && i % 16 == 0) {
466 DEBUG_printf("\n");
467 }
468 DEBUG_printf(" %02x", fun_data[i]);
469 }
470 DEBUG_printf("\n");
471
Damiena1ddfcc2013-10-10 23:25:50 +0100472#ifdef WRITE_NATIVE
Damien826005c2013-10-05 23:17:28 +0100473 if (fp_native != NULL) {
474 fwrite(fun_data, len, 1, fp_native);
475 }
Damiena1ddfcc2013-10-10 23:25:50 +0100476#endif
477#endif
Damien429d7192013-10-04 19:53:11 +0100478}
479
Damiena3977762013-10-09 23:10:10 +0100480bool py_obj_is_callable(py_obj_t o_in) {
481 if (IS_SMALL_INT(o_in)) {
482 return false;
483 } else {
484 py_obj_base_t *o = o_in;
485 switch (o->kind) {
486 case O_FUN_0:
487 case O_FUN_1:
488 case O_FUN_2:
489 case O_FUN_N:
490 case O_FUN_BC:
491 case O_FUN_ASM:
Damieneb19efb2013-10-10 22:06:54 +0100492 // what about O_CLASS, and an O_OBJ that has a __call__ method?
Damiena3977762013-10-09 23:10:10 +0100493 return true;
494 default:
495 return false;
496 }
497 }
498}
499
Damien429d7192013-10-04 19:53:11 +0100500const char *py_obj_get_type_str(py_obj_t o_in) {
501 if (IS_SMALL_INT(o_in)) {
502 return "int";
503 } else {
504 py_obj_base_t *o = o_in;
505 switch (o->kind) {
506 case O_CONST:
507 if (o == py_const_none) {
508 return "NoneType";
509 } else {
510 return "bool";
511 }
512 case O_STR:
513 return "str";
Damienc025ebb2013-10-12 14:30:21 +0100514#ifdef MICROPY_ENABLE_FLOAT
Damien429d7192013-10-04 19:53:11 +0100515 case O_FLOAT:
516 return "float";
517#endif
Damien6cdd3af2013-10-05 18:08:26 +0100518 case O_FUN_0:
519 case O_FUN_1:
520 case O_FUN_2:
521 case O_FUN_N:
522 case O_FUN_BC:
523 return "function";
Damien429d7192013-10-04 19:53:11 +0100524 case O_LIST:
525 return "list";
526 case O_SET:
527 return "set";
528 case O_MAP:
529 return "dict";
Damiena3977762013-10-09 23:10:10 +0100530 case O_OBJ:
531 {
532 py_map_elem_t *qn = py_qstr_map_lookup(o->u_obj.class->u_class.locals, qstr_from_str_static("__qualname__"), false);
533 assert(qn != NULL);
534 assert(IS_O(qn->value, O_STR));
535 return qstr_str(((py_obj_base_t*)qn->value)->u_str);
536 }
Damien429d7192013-10-04 19:53:11 +0100537 default:
538 assert(0);
539 return "UnknownType";
540 }
541 }
542}
543
544void py_obj_print(py_obj_t o_in) {
545 if (IS_SMALL_INT(o_in)) {
546 printf("%d", (int)FROM_SMALL_INT(o_in));
547 } else {
548 py_obj_base_t *o = o_in;
549 switch (o->kind) {
550 case O_CONST:
551 printf("%s", o->id);
552 break;
553 case O_STR:
554 // TODO need to escape chars etc
555 printf("'%s'", qstr_str(o->u_str));
556 break;
Damienc025ebb2013-10-12 14:30:21 +0100557#ifdef MICROPY_ENABLE_FLOAT
Damien429d7192013-10-04 19:53:11 +0100558 case O_FLOAT:
Damiene4af64f2013-10-06 12:04:13 +0100559 printf("%f", o->u_flt);
Damien429d7192013-10-04 19:53:11 +0100560 break;
561#endif
562 case O_LIST:
563 printf("[");
564 for (int i = 0; i < o->u_list.len; i++) {
565 if (i > 0) {
566 printf(", ");
567 }
568 py_obj_print(o->u_list.items[i]);
569 }
570 printf("]");
571 break;
572 case O_SET:
573 {
574 bool first = true;
575 printf("{");
576 for (int i = 0; i < o->u_set.alloc; i++) {
577 if (o->u_set.table[i] != NULL) {
578 if (!first) {
579 printf(", ");
580 }
581 first = false;
582 py_obj_print(o->u_set.table[i]);
583 }
584 }
585 printf("}");
586 break;
587 }
588 case O_MAP:
589 {
590 bool first = true;
591 printf("{");
592 for (int i = 0; i < o->u_map.alloc; i++) {
593 if (o->u_map.table[i].key != NULL) {
594 if (!first) {
595 printf(", ");
596 }
597 first = false;
598 py_obj_print(o->u_map.table[i].key);
599 printf(": ");
600 py_obj_print(o->u_map.table[i].value);
601 }
602 }
603 printf("}");
604 break;
605 }
606 default:
Damiena3977762013-10-09 23:10:10 +0100607 printf("<? %d>", o->kind);
Damien429d7192013-10-04 19:53:11 +0100608 assert(0);
609 }
610 }
611}
612
613int rt_is_true(py_obj_t arg) {
614 DEBUG_OP_printf("is true %p\n", arg);
615 if (IS_SMALL_INT(arg)) {
616 if (FROM_SMALL_INT(arg) == 0) {
617 return 0;
618 } else {
619 return 1;
620 }
621 } else if (arg == py_const_none) {
622 return 0;
623 } else if (arg == py_const_false) {
624 return 0;
625 } else if (arg == py_const_true) {
626 return 1;
627 } else {
628 assert(0);
629 return 0;
630 }
631}
632
633int rt_get_int(py_obj_t arg) {
634 if (IS_SMALL_INT(arg)) {
635 return FROM_SMALL_INT(arg);
636 } else {
637 assert(0);
638 return 0;
639 }
640}
641
642py_obj_t rt_load_const_str(qstr qstr) {
643 DEBUG_OP_printf("load '%s'\n", qstr_str(qstr));
644 return py_obj_new_str(qstr);
645}
646
647py_obj_t rt_load_name(qstr qstr) {
648 // logic: search locals, globals, builtins
Damiena3977762013-10-09 23:10:10 +0100649 DEBUG_OP_printf("load name %s\n", qstr_str(qstr));
Damieneb19efb2013-10-10 22:06:54 +0100650 py_map_elem_t *elem = py_qstr_map_lookup(map_locals, qstr, false);
Damiena3977762013-10-09 23:10:10 +0100651 if (elem == NULL) {
Damieneb19efb2013-10-10 22:06:54 +0100652 elem = py_qstr_map_lookup(map_globals, qstr, false);
Damiena3977762013-10-09 23:10:10 +0100653 if (elem == NULL) {
654 elem = py_qstr_map_lookup(&map_builtins, qstr, false);
655 if (elem == NULL) {
656 printf("name doesn't exist: %s\n", qstr_str(qstr));
657 assert(0);
658 }
659 }
660 }
661 return elem->value;
662}
663
664py_obj_t rt_load_global(qstr qstr) {
665 // logic: search globals, builtins
666 DEBUG_OP_printf("load global %s\n", qstr_str(qstr));
Damieneb19efb2013-10-10 22:06:54 +0100667 py_map_elem_t *elem = py_qstr_map_lookup(map_globals, qstr, false);
Damien429d7192013-10-04 19:53:11 +0100668 if (elem == NULL) {
669 elem = py_qstr_map_lookup(&map_builtins, qstr, false);
670 if (elem == NULL) {
671 printf("name doesn't exist: %s\n", qstr_str(qstr));
672 assert(0);
673 }
674 }
675 return elem->value;
676}
677
Damien429d7192013-10-04 19:53:11 +0100678py_obj_t rt_load_build_class() {
679 DEBUG_OP_printf("load_build_class\n");
680 py_map_elem_t *elem = py_qstr_map_lookup(&map_builtins, q___build_class__, false);
681 if (elem == NULL) {
682 printf("name doesn't exist: __build_class__\n");
683 assert(0);
684 }
685 return elem->value;
686}
687
688void rt_store_name(qstr qstr, py_obj_t obj) {
Damiena3977762013-10-09 23:10:10 +0100689 DEBUG_OP_printf("store name %s <- %p\n", qstr_str(qstr), obj);
Damieneb19efb2013-10-10 22:06:54 +0100690 py_qstr_map_lookup(map_locals, qstr, true)->value = obj;
Damiena3977762013-10-09 23:10:10 +0100691}
692
693void rt_store_global(qstr qstr, py_obj_t obj) {
694 DEBUG_OP_printf("store global %s <- %p\n", qstr_str(qstr), obj);
Damieneb19efb2013-10-10 22:06:54 +0100695 py_qstr_map_lookup(map_globals, qstr, true)->value = obj;
Damien429d7192013-10-04 19:53:11 +0100696}
697
698py_obj_t rt_unary_op(int op, py_obj_t arg) {
699 assert(0);
700 return py_const_none;
701}
702
703py_obj_t rt_binary_op(int op, py_obj_t lhs, py_obj_t rhs) {
704 DEBUG_OP_printf("binary %d %p %p\n", op, lhs, rhs);
705 if (op == RT_BINARY_OP_SUBSCR) {
706 if (IS_O(lhs, O_LIST) && IS_SMALL_INT(rhs)) {
707 return ((py_obj_base_t*)lhs)->u_list.items[FROM_SMALL_INT(rhs)];
708 } else {
709 assert(0);
710 }
711 } else if (IS_SMALL_INT(lhs) && IS_SMALL_INT(rhs)) {
712 py_small_int_t val;
713 switch (op) {
714 case RT_BINARY_OP_ADD:
715 case RT_BINARY_OP_INPLACE_ADD: val = FROM_SMALL_INT(lhs) + FROM_SMALL_INT(rhs); break;
716 case RT_BINARY_OP_SUBTRACT: val = FROM_SMALL_INT(lhs) - FROM_SMALL_INT(rhs); break;
717 case RT_BINARY_OP_MULTIPLY: val = FROM_SMALL_INT(lhs) * FROM_SMALL_INT(rhs); break;
718 case RT_BINARY_OP_FLOOR_DIVIDE: val = FROM_SMALL_INT(lhs) / FROM_SMALL_INT(rhs); break;
Damienc025ebb2013-10-12 14:30:21 +0100719#ifdef MICROPY_ENABLE_FLOAT
Damien429d7192013-10-04 19:53:11 +0100720 case RT_BINARY_OP_TRUE_DIVIDE: return py_obj_new_float((float_t)FROM_SMALL_INT(lhs) / (float_t)FROM_SMALL_INT(rhs));
721#endif
722 default: printf("%d\n", op); assert(0); val = 0;
723 }
724 if (fit_small_int(val)) {
725 return TO_SMALL_INT(val);
726 }
727 } else if (IS_O(lhs, O_STR) && IS_O(rhs, O_STR)) {
728 const char *lhs_str = qstr_str(((py_obj_base_t*)lhs)->u_str);
729 const char *rhs_str = qstr_str(((py_obj_base_t*)rhs)->u_str);
730 char *val;
731 switch (op) {
732 case RT_BINARY_OP_ADD:
733 case RT_BINARY_OP_INPLACE_ADD: val = m_new(char, strlen(lhs_str) + strlen(rhs_str) + 1); strcpy(val, lhs_str); strcat(val, rhs_str); break;
734 default: printf("%d\n", op); assert(0); val = NULL;
735 }
736 return py_obj_new_str(qstr_from_str_take(val));
737 }
738 assert(0);
739 return py_const_none;
740}
741
742py_obj_t rt_compare_op(int op, py_obj_t lhs, py_obj_t rhs) {
743 DEBUG_OP_printf("compare %d %p %p\n", op, lhs, rhs);
744 if (IS_SMALL_INT(lhs) && IS_SMALL_INT(rhs)) {
745 int cmp;
746 switch (op) {
747 case RT_COMPARE_OP_LESS: cmp = FROM_SMALL_INT(lhs) < FROM_SMALL_INT(rhs); break;
748 case RT_COMPARE_OP_MORE: cmp = FROM_SMALL_INT(lhs) > FROM_SMALL_INT(rhs); break;
749 default: assert(0); cmp = 0;
750 }
751 if (cmp) {
752 return py_const_true;
753 } else {
754 return py_const_false;
755 }
756 }
757 assert(0);
758 return py_const_none;
759}
760
761py_obj_t rt_make_function_from_id(int unique_code_id) {
Damienb05d7072013-10-05 13:37:10 +0100762 DEBUG_OP_printf("make_function_from_id %d\n", unique_code_id);
763 if (unique_code_id < 1 || unique_code_id >= next_unique_code_id) {
Damien429d7192013-10-04 19:53:11 +0100764 // illegal code id
765 return py_const_none;
766 }
767 py_code_t *c = &unique_codes[unique_code_id];
768 py_obj_base_t *o = m_new(py_obj_base_t, 1);
769 switch (c->kind) {
Damien826005c2013-10-05 23:17:28 +0100770 case PY_CODE_BYTE:
771 o->kind = O_FUN_BC;
772 o->u_fun_bc.n_args = c->n_args;
773 o->u_fun_bc.code = c->u_byte.code;
774 o->u_fun_bc.len = c->u_byte.len;
775 break;
Damien429d7192013-10-04 19:53:11 +0100776 case PY_CODE_NATIVE:
777 switch (c->n_args) {
778 case 0: o->kind = O_FUN_0; break;
779 case 1: o->kind = O_FUN_1; break;
780 case 2: o->kind = O_FUN_2; break;
781 default: assert(0);
782 }
783 o->u_fun.fun = c->u_native.fun;
784 break;
Damien826005c2013-10-05 23:17:28 +0100785 case PY_CODE_INLINE_ASM:
786 o->kind = O_FUN_ASM;
787 o->u_fun_asm.n_args = c->n_args;
788 o->u_fun_asm.fun = c->u_inline_asm.fun;
Damien429d7192013-10-04 19:53:11 +0100789 break;
790 default:
791 assert(0);
792 }
793 return o;
794}
795
796py_obj_t rt_make_function_0(py_fun_0_t fun) {
797 py_obj_base_t *o = m_new(py_obj_base_t, 1);
798 o->kind = O_FUN_0;
799 o->u_fun.fun = fun;
800 return o;
801}
802
803py_obj_t rt_make_function_1(py_fun_1_t fun) {
804 py_obj_base_t *o = m_new(py_obj_base_t, 1);
805 o->kind = O_FUN_1;
806 o->u_fun.fun = fun;
807 return o;
808}
809
810py_obj_t rt_make_function_2(py_fun_2_t fun) {
811 py_obj_base_t *o = m_new(py_obj_base_t, 1);
812 o->kind = O_FUN_2;
813 o->u_fun.fun = fun;
814 return o;
815}
816
817py_obj_t rt_make_function(int n_args, py_fun_t code) {
818 // assumes code is a pointer to a py_fun_t (i think this is safe...)
819 py_obj_base_t *o = m_new(py_obj_base_t, 1);
820 o->kind = O_FUN_N;
Damien429d7192013-10-04 19:53:11 +0100821 o->u_fun.n_args = n_args;
Damien826005c2013-10-05 23:17:28 +0100822 o->u_fun.fun = code;
Damien429d7192013-10-04 19:53:11 +0100823 return o;
824}
825
Damieneb19efb2013-10-10 22:06:54 +0100826py_obj_t rt_call_function_0(py_obj_t fun) {
827 return rt_call_function_n(fun, 0, NULL);
828}
829
830py_obj_t rt_call_function_1(py_obj_t fun, py_obj_t arg) {
831 return rt_call_function_n(fun, 1, &arg);
832}
833
834py_obj_t rt_call_function_2(py_obj_t fun, py_obj_t arg1, py_obj_t arg2) {
835 py_obj_t args[2];
836 args[1] = arg1;
837 args[0] = arg2;
838 return rt_call_function_n(fun, 2, args);
839}
840
841typedef machine_uint_t (*inline_asm_fun_0_t)();
842typedef machine_uint_t (*inline_asm_fun_1_t)(machine_uint_t);
843typedef machine_uint_t (*inline_asm_fun_2_t)(machine_uint_t, machine_uint_t);
844typedef machine_uint_t (*inline_asm_fun_3_t)(machine_uint_t, machine_uint_t, machine_uint_t);
845
Damiene4af64f2013-10-06 12:04:13 +0100846// convert a Python object to a sensible value for inline asm
847machine_uint_t rt_convert_obj_for_inline_asm(py_obj_t obj) {
848 // TODO for byte_array, pass pointer to the array
849 if (IS_SMALL_INT(obj)) {
850 return FROM_SMALL_INT(obj);
851 } else if (obj == py_const_none) {
852 return 0;
853 } else if (obj == py_const_false) {
854 return 0;
855 } else if (obj == py_const_true) {
856 return 1;
857 } else {
858 py_obj_base_t *o = obj;
859 switch (o->kind) {
860 case O_STR:
861 // pointer to the string (it's probably constant though!)
862 return (machine_uint_t)qstr_str(o->u_str);
863
Damienc025ebb2013-10-12 14:30:21 +0100864#ifdef MICROPY_ENABLE_FLOAT
Damiene4af64f2013-10-06 12:04:13 +0100865 case O_FLOAT:
866 // convert float to int (could also pass in float registers)
867 return (machine_int_t)o->u_flt;
Damienc025ebb2013-10-12 14:30:21 +0100868#endif
Damiene4af64f2013-10-06 12:04:13 +0100869
870 case O_LIST:
871 // pointer to start of list (could pass length, but then could use len(x) for that)
872 return (machine_uint_t)o->u_list.items;
873
874 default:
875 // just pass along a pointer to the object
876 return (machine_uint_t)obj;
877 }
878 }
879}
880
881// convert a return value from inline asm to a sensible Python object
882py_obj_t rt_convert_val_from_inline_asm(machine_uint_t val) {
883 return TO_SMALL_INT(val);
884}
885
Damieneb19efb2013-10-10 22:06:54 +0100886// args are in reverse order in the array
887py_obj_t rt_call_function_n(py_obj_t fun, int n_args, const py_obj_t *args) {
888 int n_args_fun = 0;
Damien429d7192013-10-04 19:53:11 +0100889 if (IS_O(fun, O_FUN_0)) {
890 py_obj_base_t *o = fun;
Damieneb19efb2013-10-10 22:06:54 +0100891 if (n_args != 0) {
892 n_args_fun = 0;
893 goto bad_n_args;
894 }
895 DEBUG_OP_printf("calling native %p()\n", o->u_fun.fun);
Damien429d7192013-10-04 19:53:11 +0100896 return ((py_fun_0_t)o->u_fun.fun)();
Damieneb19efb2013-10-10 22:06:54 +0100897
898 } else if (IS_O(fun, O_FUN_1)) {
899 py_obj_base_t *o = fun;
900 if (n_args != 1) {
901 n_args_fun = 1;
902 goto bad_n_args;
903 }
904 DEBUG_OP_printf("calling native %p(%p)\n", o->u_fun.fun, args[0]);
905 return ((py_fun_1_t)o->u_fun.fun)(args[0]);
906
907 } else if (IS_O(fun, O_FUN_2)) {
908 py_obj_base_t *o = fun;
909 if (n_args != 2) {
910 n_args_fun = 2;
911 goto bad_n_args;
912 }
913 DEBUG_OP_printf("calling native %p(%p, %p)\n", o->u_fun.fun, args[1], args[0]);
914 return ((py_fun_2_t)o->u_fun.fun)(args[1], args[0]);
915
916 // TODO O_FUN_N
917
Damien429d7192013-10-04 19:53:11 +0100918 } else if (IS_O(fun, O_FUN_BC)) {
919 py_obj_base_t *o = fun;
Damieneb19efb2013-10-10 22:06:54 +0100920 if (n_args != o->u_fun_bc.n_args) {
921 n_args_fun = o->u_fun_bc.n_args;
922 goto bad_n_args;
923 }
924 DEBUG_OP_printf("calling byte code %p(n_args=%d)\n", o->u_fun_bc.code, n_args);
925 return py_execute_byte_code(o->u_fun_bc.code, o->u_fun_bc.len, args, n_args);
926
Damiene4af64f2013-10-06 12:04:13 +0100927 } else if (IS_O(fun, O_FUN_ASM)) {
928 py_obj_base_t *o = fun;
Damieneb19efb2013-10-10 22:06:54 +0100929 if (n_args != o->u_fun_asm.n_args) {
930 n_args_fun = o->u_fun_asm.n_args;
931 goto bad_n_args;
932 }
933 DEBUG_OP_printf("calling inline asm %p(n_args=%d)\n", o->u_fun_asm.fun, n_args);
934 machine_uint_t ret;
935 if (n_args == 0) {
936 ret = ((inline_asm_fun_0_t)o->u_fun_asm.fun)();
937 } else if (n_args == 1) {
938 ret = ((inline_asm_fun_1_t)o->u_fun_asm.fun)(rt_convert_obj_for_inline_asm(args[0]));
939 } else if (n_args == 2) {
940 ret = ((inline_asm_fun_2_t)o->u_fun_asm.fun)(rt_convert_obj_for_inline_asm(args[1]), rt_convert_obj_for_inline_asm(args[0]));
941 } else if (n_args == 3) {
942 ret = ((inline_asm_fun_3_t)o->u_fun_asm.fun)(rt_convert_obj_for_inline_asm(args[2]), rt_convert_obj_for_inline_asm(args[1]), rt_convert_obj_for_inline_asm(args[0]));
943 } else {
944 assert(0);
945 ret = 0;
946 }
947 return rt_convert_val_from_inline_asm(ret);
948
Damiena3977762013-10-09 23:10:10 +0100949 } else if (IS_O(fun, O_BOUND_METH)) {
950 py_obj_base_t *o = fun;
Damieneb19efb2013-10-10 22:06:54 +0100951 DEBUG_OP_printf("calling bound method %p(self=%p, n_args=%d)\n", o->u_bound_meth.meth, o->u_bound_meth.self, n_args);
952 if (n_args == 0) {
953 return rt_call_function_n(o->u_bound_meth.meth, 1, &o->u_bound_meth.self);
954 } else if (n_args == 1) {
955 py_obj_t args2[2];
956 args2[1] = o->u_bound_meth.self;
957 args2[0] = args[0];
958 return rt_call_function_n(o->u_bound_meth.meth, 2, args2);
959 } else {
960 // TODO not implemented
961 assert(0);
962 return py_const_none;
963 //return rt_call_function_2(o->u_bound_meth.meth, n_args + 1, o->u_bound_meth.self + args);
964 }
965
Damiena3977762013-10-09 23:10:10 +0100966 } else if (IS_O(fun, O_CLASS)) {
967 // instantiate an instance of a class
Damieneb19efb2013-10-10 22:06:54 +0100968 if (n_args != 0) {
969 n_args_fun = 0;
970 goto bad_n_args;
971 }
Damiena3977762013-10-09 23:10:10 +0100972 DEBUG_OP_printf("instantiate object of class %p with no args\n", fun);
973 py_obj_base_t *o = m_new(py_obj_base_t, 1);
974 o->kind = O_OBJ;
975 o->u_obj.class = fun;
976 o->u_obj.members = py_map_new(MAP_QSTR, 0);
977 return o;
Damieneb19efb2013-10-10 22:06:54 +0100978
Damien429d7192013-10-04 19:53:11 +0100979 } else {
Damieneb19efb2013-10-10 22:06:54 +0100980 printf("fun %p %d\n", fun, ((py_obj_base_t*)fun)->kind);
Damien429d7192013-10-04 19:53:11 +0100981 assert(0);
982 return py_const_none;
983 }
Damien429d7192013-10-04 19:53:11 +0100984
Damieneb19efb2013-10-10 22:06:54 +0100985bad_n_args:
986 printf("TypeError: function takes %d positional arguments but %d were given\n", n_args_fun, n_args);
987 assert(0);
988 return py_const_none;
Damien429d7192013-10-04 19:53:11 +0100989}
990
Damiena3977762013-10-09 23:10:10 +0100991// args contains: arg(n_args-1) arg(n_args-2) ... arg(0) self/NULL fun
992// if n_args==0 then there are only self/NULL and fun
993py_obj_t rt_call_method_n(int n_args, const py_obj_t *args) {
Damien7f5dacf2013-10-10 11:24:39 +0100994 DEBUG_OP_printf("call method %p(self=%p, n_args=%d)\n", args[n_args + 1], args[n_args], n_args);
Damiena3977762013-10-09 23:10:10 +0100995 return rt_call_function_n(args[n_args + 1], n_args + ((args[n_args] == NULL) ? 0 : 1), args);
996}
997
Damien429d7192013-10-04 19:53:11 +0100998// items are in reverse order
999py_obj_t rt_build_list(int n_args, py_obj_t *items) {
1000 py_obj_base_t *o = m_new(py_obj_base_t, 1);
1001 o->kind = O_LIST;
1002 o->u_list.alloc = n_args;
1003 if (o->u_list.alloc < 4) {
1004 o->u_list.alloc = 4;
1005 }
1006 o->u_list.len = n_args;
1007 o->u_list.items = m_new(py_obj_t, o->u_list.alloc);
1008 for (int i = 0; i < n_args; i++) {
1009 o->u_list.items[i] = items[n_args - i - 1];
1010 }
1011 return o;
1012}
1013
1014py_obj_t py_set_lookup(py_obj_t o_in, py_obj_t index, bool add_if_not_found) {
1015 assert(IS_O(o_in, O_SET));
1016 py_obj_base_t *o = o_in;
1017 int hash = py_obj_hash(index);
1018 int pos = hash % o->u_set.alloc;
1019 for (;;) {
1020 py_obj_t elem = o->u_set.table[pos];
1021 if (elem == NULL) {
1022 // not in table
1023 if (add_if_not_found) {
1024 if (o->u_set.used + 1 >= o->u_set.alloc) {
1025 // not enough room in table, rehash it
1026 int old_alloc = o->u_set.alloc;
1027 py_obj_t *old_table = o->u_set.table;
1028 o->u_set.alloc = get_doubling_prime_greater_or_equal_to(o->u_set.alloc + 1);
1029 o->u_set.used = 0;
1030 o->u_set.table = m_new(py_obj_t, o->u_set.alloc);
1031 for (int i = 0; i < old_alloc; i++) {
1032 if (old_table[i] != NULL) {
1033 py_set_lookup(o, old_table[i], true);
1034 }
1035 }
1036 m_free(old_table);
1037 // restart the search for the new element
1038 pos = hash % o->u_set.alloc;
1039 } else {
1040 o->u_set.used += 1;
1041 o->u_set.table[pos] = index;
1042 return index;
1043 }
1044 } else {
1045 return NULL;
1046 }
1047 } else if (py_obj_equal(elem, index)) {
1048 // found it
1049 return elem;
1050 } else {
1051 // not yet found, keep searching in this table
1052 pos = (pos + 1) % o->u_set.alloc;
1053 }
1054 }
1055}
1056
1057py_obj_t rt_build_set(int n_args, py_obj_t *items) {
1058 py_obj_base_t *o = m_new(py_obj_base_t, 1);
1059 o->kind = O_SET;
1060 o->u_set.alloc = get_doubling_prime_greater_or_equal_to(n_args + 1);
1061 o->u_set.used = 0;
1062 o->u_set.table = m_new(py_obj_t, o->u_set.alloc);
1063 for (int i = 0; i < o->u_set.alloc; i++) {
1064 o->u_set.table[i] = NULL;
1065 }
1066 for (int i = 0; i < n_args; i++) {
1067 py_set_lookup(o, items[i], true);
1068 }
1069 return o;
1070}
1071
1072py_obj_t rt_build_map(int n_args) {
1073 py_obj_base_t *o = m_new(py_obj_base_t, 1);
1074 o->kind = O_MAP;
1075 py_map_init(&o->u_map, MAP_PY_OBJ, n_args);
1076 return o;
1077}
1078
1079py_obj_t rt_store_map(py_obj_t map, py_obj_t key, py_obj_t value) {
1080 assert(IS_O(map, O_MAP)); // should always be
1081 py_map_lookup(map, key, true)->value = value;
1082 return map;
1083}
1084
Damiena3977762013-10-09 23:10:10 +01001085py_obj_t build_bound_method(py_obj_t self, py_obj_t meth) {
1086 py_obj_base_t *o = m_new(py_obj_base_t, 1);
1087 o->kind = O_BOUND_METH;
1088 o->u_bound_meth.meth = meth;
1089 o->u_bound_meth.self = self;
1090 return o;
1091}
1092
1093py_obj_t rt_load_attr(py_obj_t base, qstr attr) {
1094 DEBUG_OP_printf("load attr %s\n", qstr_str(attr));
1095 if (IS_O(base, O_LIST) && attr == q_append) {
1096 return build_bound_method(base, fun_list_append);
1097 } else if (IS_O(base, O_CLASS)) {
1098 py_obj_base_t *o = base;
1099 py_map_elem_t *elem = py_qstr_map_lookup(o->u_class.locals, attr, false);
1100 if (elem == NULL) {
1101 goto no_attr;
1102 }
1103 return elem->value;
1104 } else if (IS_O(base, O_OBJ)) {
1105 // logic: look in obj members then class locals (TODO check this against CPython)
1106 py_obj_base_t *o = base;
1107 py_map_elem_t *elem = py_qstr_map_lookup(o->u_obj.members, attr, false);
1108 if (elem != NULL) {
1109 // object member, always treated as a value
1110 return elem->value;
1111 }
1112 elem = py_qstr_map_lookup(o->u_obj.class->u_class.locals, attr, false);
1113 if (elem != NULL) {
1114 if (py_obj_is_callable(elem->value)) {
1115 // class member is callable so build a bound method
1116 return build_bound_method(base, elem->value);
1117 } else {
1118 // class member is a value, so just return that value
1119 return elem->value;
1120 }
1121 }
1122 goto no_attr;
1123 }
1124
1125no_attr:
1126 printf("AttributeError: '%s' object has no attribute '%s'\n", py_obj_get_type_str(base), qstr_str(attr));
1127 assert(0);
1128 return py_const_none;
1129}
1130
1131void rt_load_method(py_obj_t base, qstr attr, py_obj_t *dest) {
1132 DEBUG_OP_printf("load method %s\n", qstr_str(attr));
1133 if (IS_O(base, O_LIST) && attr == q_append) {
1134 dest[1] = fun_list_append;
1135 dest[0] = base;
1136 return;
1137 } else if (IS_O(base, O_OBJ)) {
1138 // logic: look in obj members then class locals (TODO check this against CPython)
1139 py_obj_base_t *o = base;
1140 py_map_elem_t *elem = py_qstr_map_lookup(o->u_obj.members, attr, false);
1141 if (elem != NULL) {
1142 // object member, always treated as a value
1143 dest[1] = elem->value;
1144 dest[0] = NULL;
1145 return;
1146 }
1147 elem = py_qstr_map_lookup(o->u_obj.class->u_class.locals, attr, false);
1148 if (elem != NULL) {
1149 if (py_obj_is_callable(elem->value)) {
1150 // class member is callable so build a bound method
1151 dest[1] = elem->value;
1152 dest[0] = base;
1153 return;
1154 } else {
1155 // class member is a value, so just return that value
1156 dest[1] = elem->value;
1157 dest[0] = NULL;
1158 return;
1159 }
1160 }
1161 goto no_attr;
1162 }
1163
1164no_attr:
1165 dest[1] = rt_load_attr(base, attr);
1166 dest[0] = NULL;
1167}
1168
1169void rt_store_attr(py_obj_t base, qstr attr, py_obj_t val) {
1170 DEBUG_OP_printf("store attr %p.%s <- %p\n", base, qstr_str(attr), val);
1171 if (IS_O(base, O_OBJ)) {
1172 // logic: look in class locals (no add) then obj members (add) (TODO check this against CPython)
1173 py_obj_base_t *o = base;
1174 py_map_elem_t *elem = py_qstr_map_lookup(o->u_obj.class->u_class.locals, attr, false);
1175 if (elem != NULL) {
1176 elem->value = val;
1177 } else {
1178 elem = py_qstr_map_lookup(o->u_obj.class->u_class.locals, attr, true)->value = val;
1179 }
1180 } else {
1181 printf("?AttributeError: '%s' object has no attribute '%s'\n", py_obj_get_type_str(base), qstr_str(attr));
1182 assert(0);
1183 }
1184}
1185
Damien429d7192013-10-04 19:53:11 +01001186void rt_store_subscr(py_obj_t base, py_obj_t index, py_obj_t value) {
1187 if (IS_O(base, O_LIST) && IS_SMALL_INT(index)) {
1188 // list store
1189 py_obj_base_t *o = base;
1190 int idx = FROM_SMALL_INT(index);
1191 if (idx < 0) {
1192 idx += o->u_list.len;
1193 }
1194 if (0 <= idx && idx < o->u_list.len) {
1195 o->u_list.items[idx] = value;
1196 } else {
1197 assert(0);
1198 }
1199 } else if (IS_O(base, O_MAP)) {
1200 // map store
1201 py_map_lookup(base, index, true)->value = value;
1202 } else {
1203 assert(0);
1204 }
1205}
1206
Damien429d7192013-10-04 19:53:11 +01001207void *rt_fun_table[RT_F_NUMBER_OF] = {
1208 rt_load_const_str,
1209 rt_load_name,
1210 rt_load_global,
Damien7f5dacf2013-10-10 11:24:39 +01001211 rt_load_build_class,
Damien429d7192013-10-04 19:53:11 +01001212 rt_load_attr,
1213 rt_load_method,
1214 rt_store_name,
Damien7f5dacf2013-10-10 11:24:39 +01001215 rt_store_attr,
Damien429d7192013-10-04 19:53:11 +01001216 rt_store_subscr,
1217 rt_is_true,
1218 rt_unary_op,
1219 rt_build_list,
1220 rt_build_map,
1221 rt_store_map,
1222 rt_build_set,
1223 rt_make_function_from_id,
Damieneb19efb2013-10-10 22:06:54 +01001224 rt_call_function_n,
Damien7f5dacf2013-10-10 11:24:39 +01001225 rt_call_method_n,
Damien429d7192013-10-04 19:53:11 +01001226 rt_binary_op,
1227 rt_compare_op,
1228};
1229
1230/*
1231void rt_f_vector(rt_fun_kind_t fun_kind) {
1232 (rt_f_table[fun_kind])();
1233}
1234*/