blob: 7e7164d4f0b79a0cce8c41327416935af506c170 [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"
8#include "machine.h"
9#include "runtime.h"
Damienb05d7072013-10-05 13:37:10 +010010#include "vm.h"
Damien429d7192013-10-04 19:53:11 +010011
Damiena3977762013-10-09 23:10:10 +010012#define DEBUG_printf(args...) (void)0
13//#define DEBUG_printf(args...) printf(args)
Damien429d7192013-10-04 19:53:11 +010014
15#define DEBUG_OP_printf(args...) (void)0
16//#define DEBUG_OP_printf(args...) printf(args)
17
18// enable/disable float support with this definition
19#define PY_FLOAT (1)
20
21typedef machine_int_t py_small_int_t;
22
23#define IS_O(o, k) (((((py_small_int_t)(o)) & 1) == 0) && (((py_obj_base_t*)(o))->kind == (k)))
24#define IS_SMALL_INT(o) (((py_small_int_t)(o)) & 1)
25#define FROM_SMALL_INT(o) (((py_small_int_t)(o)) >> 1)
26#define TO_SMALL_INT(o) ((py_obj_t)(((o) << 1) | 1))
27
28#ifdef PY_FLOAT
29typedef machine_float_t float_t;
30#endif
31
32typedef enum {
33 O_CONST,
34 O_STR,
35#ifdef PY_FLOAT
36 O_FLOAT,
37#endif
38 O_FUN_0,
39 O_FUN_1,
40 O_FUN_2,
41 O_FUN_N,
42 O_FUN_BC,
Damien826005c2013-10-05 23:17:28 +010043 O_FUN_ASM,
Damien429d7192013-10-04 19:53:11 +010044 O_BOUND_METH,
45 O_LIST,
46 O_SET,
47 O_MAP,
48 O_CLASS,
Damiena3977762013-10-09 23:10:10 +010049 O_OBJ,
Damien429d7192013-10-04 19:53:11 +010050} py_obj_kind_t;
51
52typedef enum {
53 MAP_QSTR,
54 MAP_PY_OBJ,
55} py_map_kind_t;
56
57typedef struct _py_map_elem_t {
58 py_obj_t key;
59 py_obj_t value;
60} py_map_elem_t;
61
62typedef struct _py_map_t {
Damiena3977762013-10-09 23:10:10 +010063 py_map_kind_t kind; // TODO merge this 1-bit field into alloc or used
Damien429d7192013-10-04 19:53:11 +010064 machine_uint_t alloc;
65 machine_uint_t used;
66 py_map_elem_t *table;
67} py_map_t;
68
Damiena3977762013-10-09 23:10:10 +010069typedef struct _py_obj_base_t py_obj_base_t;
70
71struct _py_obj_base_t {
Damien429d7192013-10-04 19:53:11 +010072 py_obj_kind_t kind;
73 union {
74 const char *id;
75 qstr u_str;
76#ifdef PY_FLOAT
Damiene4af64f2013-10-06 12:04:13 +010077 float_t u_flt;
Damien429d7192013-10-04 19:53:11 +010078#endif
79 struct { // for O_FUN_[012N]
Damien429d7192013-10-04 19:53:11 +010080 int n_args;
Damien826005c2013-10-05 23:17:28 +010081 void *fun;
Damien429d7192013-10-04 19:53:11 +010082 } u_fun;
83 struct { // for O_FUN_BC
Damien826005c2013-10-05 23:17:28 +010084 int n_args;
Damien429d7192013-10-04 19:53:11 +010085 byte *code;
86 uint len;
Damien429d7192013-10-04 19:53:11 +010087 } u_fun_bc;
Damien826005c2013-10-05 23:17:28 +010088 struct { // for O_FUN_ASM
89 int n_args;
90 void *fun;
91 } u_fun_asm;
Damien429d7192013-10-04 19:53:11 +010092 struct { // for O_BOUND_METH
93 py_obj_t meth;
94 py_obj_t self;
95 } u_bound_meth;
96 struct { // for O_LIST
97 int alloc;
98 int len;
99 py_obj_t *items;
100 } u_list;
101 struct { // for O_SET
102 int alloc;
103 int used;
104 py_obj_t *table;
105 } u_set;
106 py_map_t u_map; // for O_MAP
Damien429d7192013-10-04 19:53:11 +0100107 struct { // for O_CLASS
Damiena3977762013-10-09 23:10:10 +0100108 py_map_t *locals;
Damien429d7192013-10-04 19:53:11 +0100109 } u_class;
Damiena3977762013-10-09 23:10:10 +0100110 struct { // for O_OBJ
111 py_obj_base_t *class; // points to a O_CLASS object
112 py_map_t *members;
113 } u_obj;
Damien429d7192013-10-04 19:53:11 +0100114 };
Damiena3977762013-10-09 23:10:10 +0100115};
Damien429d7192013-10-04 19:53:11 +0100116
117py_obj_t py_const_none;
118py_obj_t py_const_false;
119py_obj_t py_const_true;
120
Damiena3977762013-10-09 23:10:10 +0100121py_map_t map_locals;
122py_map_t map_globals;
Damien429d7192013-10-04 19:53:11 +0100123py_map_t map_builtins;
124
125// approximatelly doubling primes; made with Mathematica command: Table[Prime[Floor[(1.7)^n]], {n, 3, 24}]
126static 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};
127
128int get_doubling_prime_greater_or_equal_to(int x) {
129 for (int i = 0; i < sizeof(doubling_primes) / sizeof(int); i++) {
130 if (doubling_primes[i] >= x) {
131 return doubling_primes[i];
132 }
133 }
134 // ran out of primes in the table!
135 // return something sensible, at least make it odd
136 return x | 1;
137}
138
139void py_map_init(py_map_t *map, py_map_kind_t kind, int n) {
140 map->kind = kind;
141 map->alloc = get_doubling_prime_greater_or_equal_to(n + 1);
142 map->used = 0;
143 map->table = m_new(py_map_elem_t, map->alloc);
144 for (int i = 0; i < map->alloc; i++) {
145 map->table[i].key = NULL;
146 map->table[i].value = NULL;
147 }
148}
149
150py_map_t *py_map_new(py_map_kind_t kind, int n) {
151 py_map_t *map = m_new(py_map_t, 1);
152 py_map_init(map, kind, n);
153 return map;
154}
155
156int py_obj_hash(py_obj_t o_in) {
157 if (IS_SMALL_INT(o_in)) {
158 return FROM_SMALL_INT(o_in);
159 } else if (IS_O(o_in, O_STR)) {
160 return ((py_obj_base_t*)o_in)->u_str;
161 } else {
162 assert(0);
163 return 0;
164 }
165}
166
167bool py_obj_equal(py_obj_t o1, py_obj_t o2) {
168 if (o1 == o2) {
169 return true;
170 } else if (IS_SMALL_INT(o1) && IS_SMALL_INT(o2)) {
171 return false;
172 } else if (IS_O(o1, O_STR) && IS_O(o2, O_STR)) {
173 return ((py_obj_base_t*)o1)->u_str == ((py_obj_base_t*)o2)->u_str;
174 } else {
175 assert(0);
176 return false;
177 }
178}
179
180py_map_elem_t* py_map_lookup_helper(py_map_t *map, py_obj_t index, bool add_if_not_found) {
181 bool is_map_py_obj = (map->kind == MAP_PY_OBJ);
182 machine_uint_t hash;
183 if (is_map_py_obj) {
184 hash = py_obj_hash(index);
185 } else {
186 hash = (machine_uint_t)index;
187 }
188 uint pos = hash % map->alloc;
189 for (;;) {
190 py_map_elem_t *elem = &map->table[pos];
191 if (elem->key == NULL) {
192 // not in table
193 if (add_if_not_found) {
194 if (map->used + 1 >= map->alloc) {
195 // not enough room in table, rehash it
196 int old_alloc = map->alloc;
197 py_map_elem_t *old_table = map->table;
198 map->alloc = get_doubling_prime_greater_or_equal_to(map->alloc + 1);
199 map->used = 0;
200 map->table = m_new(py_map_elem_t, map->alloc);
201 for (int i = 0; i < old_alloc; i++) {
202 if (old_table[i].key != NULL) {
203 py_map_lookup_helper(map, old_table[i].key, true)->value = old_table[i].value;
204 }
205 }
206 m_free(old_table);
207 // restart the search for the new element
208 pos = hash % map->alloc;
209 } else {
210 map->used += 1;
211 elem->key = index;
212 return elem;
213 }
214 } else {
215 return NULL;
216 }
217 } else if (elem->key == index || (is_map_py_obj && py_obj_equal(elem->key, index))) {
218 // found it
219 if (add_if_not_found) {
220 elem->key = index;
221 }
222 return elem;
223 } else {
224 // not yet found, keep searching in this table
225 pos = (pos + 1) % map->alloc;
226 }
227 }
228}
229
230py_map_elem_t* py_qstr_map_lookup(py_map_t *map, qstr index, bool add_if_not_found) {
231 py_obj_t o = (py_obj_t)(machine_uint_t)index;
232 return py_map_lookup_helper(map, o, add_if_not_found);
233}
234
235py_map_elem_t* py_map_lookup(py_obj_t o, py_obj_t index, bool add_if_not_found) {
236 assert(IS_O(o, O_MAP));
237 return py_map_lookup_helper(&((py_obj_base_t *)o)->u_map, index, add_if_not_found);
238}
239
240static bool fit_small_int(py_small_int_t o) {
241 return true;
242}
243
244py_obj_t py_obj_new_const(const char *id) {
245 py_obj_base_t *o = m_new(py_obj_base_t, 1);
246 o->kind = O_CONST;
247 o->id = id;
248 return (py_obj_t)o;
249}
250
251py_obj_t py_obj_new_str(qstr qstr) {
252 py_obj_base_t *o = m_new(py_obj_base_t, 1);
253 o->kind = O_STR;
254 o->u_str = qstr;
255 return (py_obj_t)o;
256}
257
258#ifdef PY_FLOAT
259py_obj_t py_obj_new_float(float_t val) {
260 py_obj_base_t *o = m_new(py_obj_base_t, 1);
261 o->kind = O_FLOAT;
Damiene4af64f2013-10-06 12:04:13 +0100262 o->u_flt = val;
Damien429d7192013-10-04 19:53:11 +0100263 return (py_obj_t)o;
264}
265#endif
266
267py_obj_t list_append(py_obj_t self_in, py_obj_t arg) {
268 assert(IS_O(self_in, O_LIST));
269 py_obj_base_t *self = self_in;
270 if (self->u_list.len >= self->u_list.alloc) {
271 self->u_list.alloc *= 2;
272 self->u_list.items = m_renew(py_obj_t, self->u_list.items, self->u_list.alloc);
273 }
274 self->u_list.items[self->u_list.len++] = arg;
275 return arg;
276}
277
278static qstr q_append;
279static qstr q_print;
280static qstr q_len;
281static qstr q___build_class__;
282
283typedef enum {
Damien826005c2013-10-05 23:17:28 +0100284 PY_CODE_NONE,
Damien429d7192013-10-04 19:53:11 +0100285 PY_CODE_BYTE,
Damien826005c2013-10-05 23:17:28 +0100286 PY_CODE_NATIVE,
287 PY_CODE_INLINE_ASM,
Damien429d7192013-10-04 19:53:11 +0100288} py_code_kind_t;
289
290typedef struct _py_code_t {
291 py_code_kind_t kind;
292 int n_args;
293 union {
294 struct {
Damien429d7192013-10-04 19:53:11 +0100295 byte *code;
296 uint len;
297 } u_byte;
Damien826005c2013-10-05 23:17:28 +0100298 struct {
299 py_fun_t fun;
300 } u_native;
301 struct {
Damiene4af64f2013-10-06 12:04:13 +0100302 void *fun;
Damien826005c2013-10-05 23:17:28 +0100303 } u_inline_asm;
Damien429d7192013-10-04 19:53:11 +0100304 };
305} py_code_t;
306
307static int next_unique_code_id;
308static py_code_t *unique_codes;
309
310py_obj_t fun_list_append;
311
312py_obj_t py_builtin_print(py_obj_t o) {
313 if (IS_O(o, O_STR)) {
314 // special case, print string raw
315 printf("%s\n", qstr_str(((py_obj_base_t*)o)->u_str));
316 } else {
317 // print the object Python style
318 py_obj_print(o);
319 printf("\n");
320 }
321 return py_const_none;
322}
323
324py_obj_t py_builtin_len(py_obj_t o_in) {
325 py_small_int_t len = 0;
326 if (IS_O(o_in, O_LIST)) {
327 py_obj_base_t *o = o_in;
328 len = o->u_list.len;
329 } else if (IS_O(o_in, O_MAP)) {
330 py_obj_base_t *o = o_in;
331 len = o->u_map.used;
332 } else {
333 assert(0);
334 }
335 return TO_SMALL_INT(len);
336}
337
Damiena3977762013-10-09 23:10:10 +0100338py_obj_t py_builtin___build_class__(py_obj_t o_class_fun, py_obj_t o_class_name) {
339 // we differ from CPython: we set the new __locals__ object here
340 py_map_t old_locals = map_locals;
341 py_map_t *class_locals = py_map_new(MAP_QSTR, 0);
342 map_locals = *class_locals;
343
344 // call the class code
345 rt_call_function_1(o_class_fun, (py_obj_t)0xdeadbeef);
346
347 // restore old __locals__ object
348 map_locals = old_locals;
349
350 // create and return the new class
Damien429d7192013-10-04 19:53:11 +0100351 py_obj_base_t *o = m_new(py_obj_base_t, 1);
352 o->kind = O_CLASS;
Damiena3977762013-10-09 23:10:10 +0100353 o->u_class.locals = class_locals;
Damien429d7192013-10-04 19:53:11 +0100354 return o;
355}
356
357FILE *fp_native = NULL;
358
359void rt_init() {
360 q_append = qstr_from_str_static("append");
361 q_print = qstr_from_str_static("print");
362 q_len = qstr_from_str_static("len");
363 q___build_class__ = qstr_from_str_static("__build_class__");
364
365 py_const_none = py_obj_new_const("None");
366 py_const_false = py_obj_new_const("False");
367 py_const_true = py_obj_new_const("True");
368
Damiena3977762013-10-09 23:10:10 +0100369 py_map_init(&map_locals, MAP_QSTR, 0);
370
371 py_map_init(&map_globals, MAP_QSTR, 1);
372 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 +0100373
374 py_map_init(&map_builtins, MAP_QSTR, 3);
375 py_qstr_map_lookup(&map_builtins, q_print, true)->value = rt_make_function_1(py_builtin_print);
376 py_qstr_map_lookup(&map_builtins, q_len, true)->value = rt_make_function_1(py_builtin_len);
377 py_qstr_map_lookup(&map_builtins, q___build_class__, true)->value = rt_make_function_2(py_builtin___build_class__);
378
379 next_unique_code_id = 1;
380 unique_codes = NULL;
381
382 fun_list_append = rt_make_function_2(list_append);
383
384 fp_native = fopen("out-native", "wb");
385}
386
387void rt_deinit() {
388 if (fp_native != NULL) {
389 fclose(fp_native);
390 }
391}
392
393int rt_get_new_unique_code_id() {
394 return next_unique_code_id++;
395}
396
Damien826005c2013-10-05 23:17:28 +0100397static void alloc_unique_codes() {
Damien429d7192013-10-04 19:53:11 +0100398 if (unique_codes == NULL) {
399 unique_codes = m_new(py_code_t, next_unique_code_id);
Damien826005c2013-10-05 23:17:28 +0100400 for (int i = 0; i < next_unique_code_id; i++) {
401 unique_codes[i].kind = PY_CODE_NONE;
402 }
Damien429d7192013-10-04 19:53:11 +0100403 }
Damien826005c2013-10-05 23:17:28 +0100404}
405
406void rt_assign_byte_code(int unique_code_id, byte *code, uint len, int n_args) {
407 alloc_unique_codes();
408
409 assert(unique_code_id < next_unique_code_id);
410 unique_codes[unique_code_id].kind = PY_CODE_BYTE;
411 unique_codes[unique_code_id].n_args = n_args;
412 unique_codes[unique_code_id].u_byte.code = code;
413 unique_codes[unique_code_id].u_byte.len = len;
414
415 DEBUG_printf("assign byte code: id=%d code=%p len=%u n_args=%d\n", unique_code_id, code, len, n_args);
416}
417
418void rt_assign_native_code(int unique_code_id, py_fun_t fun, uint len, int n_args) {
419 alloc_unique_codes();
420
Damienb05d7072013-10-05 13:37:10 +0100421 assert(1 <= unique_code_id && unique_code_id < next_unique_code_id);
Damien429d7192013-10-04 19:53:11 +0100422 unique_codes[unique_code_id].kind = PY_CODE_NATIVE;
423 unique_codes[unique_code_id].n_args = n_args;
424 unique_codes[unique_code_id].u_native.fun = fun;
425
426 DEBUG_printf("assign native code: id=%d fun=%p len=%u n_args=%d\n", unique_code_id, fun, len, n_args);
427 byte *fun_data = (byte*)(((machine_uint_t)fun) & (~1)); // need to clear lower bit in case it's thumb code
428 for (int i = 0; i < 128 && i < len; i++) {
429 if (i > 0 && i % 16 == 0) {
430 DEBUG_printf("\n");
431 }
432 DEBUG_printf(" %02x", fun_data[i]);
433 }
434 DEBUG_printf("\n");
435
436 if (fp_native != NULL) {
437 fwrite(fun_data, len, 1, fp_native);
Damien13ed3a62013-10-08 09:05:10 +0100438 fflush(fp_native);
Damien429d7192013-10-04 19:53:11 +0100439 }
440}
441
Damien826005c2013-10-05 23:17:28 +0100442void rt_assign_inline_asm_code(int unique_code_id, py_fun_t fun, uint len, int n_args) {
443 alloc_unique_codes();
Damien429d7192013-10-04 19:53:11 +0100444
Damien826005c2013-10-05 23:17:28 +0100445 assert(1 <= unique_code_id && unique_code_id < next_unique_code_id);
446 unique_codes[unique_code_id].kind = PY_CODE_INLINE_ASM;
447 unique_codes[unique_code_id].n_args = n_args;
448 unique_codes[unique_code_id].u_inline_asm.fun = fun;
449
450 DEBUG_printf("assign inline asm code: id=%d fun=%p len=%u n_args=%d\n", unique_code_id, fun, len, n_args);
451 byte *fun_data = (byte*)(((machine_uint_t)fun) & (~1)); // need to clear lower bit in case it's thumb code
452 for (int i = 0; i < 128 && i < len; i++) {
453 if (i > 0 && i % 16 == 0) {
454 DEBUG_printf("\n");
455 }
456 DEBUG_printf(" %02x", fun_data[i]);
457 }
458 DEBUG_printf("\n");
459
460 if (fp_native != NULL) {
461 fwrite(fun_data, len, 1, fp_native);
462 }
Damien429d7192013-10-04 19:53:11 +0100463}
464
Damiena3977762013-10-09 23:10:10 +0100465bool py_obj_is_callable(py_obj_t o_in) {
466 if (IS_SMALL_INT(o_in)) {
467 return false;
468 } else {
469 py_obj_base_t *o = o_in;
470 switch (o->kind) {
471 case O_FUN_0:
472 case O_FUN_1:
473 case O_FUN_2:
474 case O_FUN_N:
475 case O_FUN_BC:
476 case O_FUN_ASM:
477 return true;
478 default:
479 return false;
480 }
481 }
482}
483
Damien429d7192013-10-04 19:53:11 +0100484const char *py_obj_get_type_str(py_obj_t o_in) {
485 if (IS_SMALL_INT(o_in)) {
486 return "int";
487 } else {
488 py_obj_base_t *o = o_in;
489 switch (o->kind) {
490 case O_CONST:
491 if (o == py_const_none) {
492 return "NoneType";
493 } else {
494 return "bool";
495 }
496 case O_STR:
497 return "str";
498#ifdef PY_FLOAT
499 case O_FLOAT:
500 return "float";
501#endif
Damien6cdd3af2013-10-05 18:08:26 +0100502 case O_FUN_0:
503 case O_FUN_1:
504 case O_FUN_2:
505 case O_FUN_N:
506 case O_FUN_BC:
507 return "function";
Damien429d7192013-10-04 19:53:11 +0100508 case O_LIST:
509 return "list";
510 case O_SET:
511 return "set";
512 case O_MAP:
513 return "dict";
Damiena3977762013-10-09 23:10:10 +0100514 case O_OBJ:
515 {
516 py_map_elem_t *qn = py_qstr_map_lookup(o->u_obj.class->u_class.locals, qstr_from_str_static("__qualname__"), false);
517 assert(qn != NULL);
518 assert(IS_O(qn->value, O_STR));
519 return qstr_str(((py_obj_base_t*)qn->value)->u_str);
520 }
Damien429d7192013-10-04 19:53:11 +0100521 default:
522 assert(0);
523 return "UnknownType";
524 }
525 }
526}
527
528void py_obj_print(py_obj_t o_in) {
529 if (IS_SMALL_INT(o_in)) {
530 printf("%d", (int)FROM_SMALL_INT(o_in));
531 } else {
532 py_obj_base_t *o = o_in;
533 switch (o->kind) {
534 case O_CONST:
535 printf("%s", o->id);
536 break;
537 case O_STR:
538 // TODO need to escape chars etc
539 printf("'%s'", qstr_str(o->u_str));
540 break;
541#ifdef PY_FLOAT
542 case O_FLOAT:
Damiene4af64f2013-10-06 12:04:13 +0100543 printf("%f", o->u_flt);
Damien429d7192013-10-04 19:53:11 +0100544 break;
545#endif
546 case O_LIST:
547 printf("[");
548 for (int i = 0; i < o->u_list.len; i++) {
549 if (i > 0) {
550 printf(", ");
551 }
552 py_obj_print(o->u_list.items[i]);
553 }
554 printf("]");
555 break;
556 case O_SET:
557 {
558 bool first = true;
559 printf("{");
560 for (int i = 0; i < o->u_set.alloc; i++) {
561 if (o->u_set.table[i] != NULL) {
562 if (!first) {
563 printf(", ");
564 }
565 first = false;
566 py_obj_print(o->u_set.table[i]);
567 }
568 }
569 printf("}");
570 break;
571 }
572 case O_MAP:
573 {
574 bool first = true;
575 printf("{");
576 for (int i = 0; i < o->u_map.alloc; i++) {
577 if (o->u_map.table[i].key != NULL) {
578 if (!first) {
579 printf(", ");
580 }
581 first = false;
582 py_obj_print(o->u_map.table[i].key);
583 printf(": ");
584 py_obj_print(o->u_map.table[i].value);
585 }
586 }
587 printf("}");
588 break;
589 }
590 default:
Damiena3977762013-10-09 23:10:10 +0100591 printf("<? %d>", o->kind);
Damien429d7192013-10-04 19:53:11 +0100592 assert(0);
593 }
594 }
595}
596
597int rt_is_true(py_obj_t arg) {
598 DEBUG_OP_printf("is true %p\n", arg);
599 if (IS_SMALL_INT(arg)) {
600 if (FROM_SMALL_INT(arg) == 0) {
601 return 0;
602 } else {
603 return 1;
604 }
605 } else if (arg == py_const_none) {
606 return 0;
607 } else if (arg == py_const_false) {
608 return 0;
609 } else if (arg == py_const_true) {
610 return 1;
611 } else {
612 assert(0);
613 return 0;
614 }
615}
616
617int rt_get_int(py_obj_t arg) {
618 if (IS_SMALL_INT(arg)) {
619 return FROM_SMALL_INT(arg);
620 } else {
621 assert(0);
622 return 0;
623 }
624}
625
626py_obj_t rt_load_const_str(qstr qstr) {
627 DEBUG_OP_printf("load '%s'\n", qstr_str(qstr));
628 return py_obj_new_str(qstr);
629}
630
631py_obj_t rt_load_name(qstr qstr) {
632 // logic: search locals, globals, builtins
Damiena3977762013-10-09 23:10:10 +0100633 DEBUG_OP_printf("load name %s\n", qstr_str(qstr));
634 py_map_elem_t *elem = py_qstr_map_lookup(&map_locals, qstr, false);
635 if (elem == NULL) {
636 elem = py_qstr_map_lookup(&map_globals, qstr, false);
637 if (elem == NULL) {
638 elem = py_qstr_map_lookup(&map_builtins, qstr, false);
639 if (elem == NULL) {
640 printf("name doesn't exist: %s\n", qstr_str(qstr));
641 assert(0);
642 }
643 }
644 }
645 return elem->value;
646}
647
648py_obj_t rt_load_global(qstr qstr) {
649 // logic: search globals, builtins
650 DEBUG_OP_printf("load global %s\n", qstr_str(qstr));
651 py_map_elem_t *elem = py_qstr_map_lookup(&map_globals, qstr, false);
Damien429d7192013-10-04 19:53:11 +0100652 if (elem == NULL) {
653 elem = py_qstr_map_lookup(&map_builtins, qstr, false);
654 if (elem == NULL) {
655 printf("name doesn't exist: %s\n", qstr_str(qstr));
656 assert(0);
657 }
658 }
659 return elem->value;
660}
661
Damien429d7192013-10-04 19:53:11 +0100662py_obj_t rt_load_build_class() {
663 DEBUG_OP_printf("load_build_class\n");
664 py_map_elem_t *elem = py_qstr_map_lookup(&map_builtins, q___build_class__, false);
665 if (elem == NULL) {
666 printf("name doesn't exist: __build_class__\n");
667 assert(0);
668 }
669 return elem->value;
670}
671
672void rt_store_name(qstr qstr, py_obj_t obj) {
Damiena3977762013-10-09 23:10:10 +0100673 DEBUG_OP_printf("store name %s <- %p\n", qstr_str(qstr), obj);
674 py_qstr_map_lookup(&map_locals, qstr, true)->value = obj;
675}
676
677void rt_store_global(qstr qstr, py_obj_t obj) {
678 DEBUG_OP_printf("store global %s <- %p\n", qstr_str(qstr), obj);
679 py_qstr_map_lookup(&map_globals, qstr, true)->value = obj;
Damien429d7192013-10-04 19:53:11 +0100680}
681
682py_obj_t rt_unary_op(int op, py_obj_t arg) {
683 assert(0);
684 return py_const_none;
685}
686
687py_obj_t rt_binary_op(int op, py_obj_t lhs, py_obj_t rhs) {
688 DEBUG_OP_printf("binary %d %p %p\n", op, lhs, rhs);
689 if (op == RT_BINARY_OP_SUBSCR) {
690 if (IS_O(lhs, O_LIST) && IS_SMALL_INT(rhs)) {
691 return ((py_obj_base_t*)lhs)->u_list.items[FROM_SMALL_INT(rhs)];
692 } else {
693 assert(0);
694 }
695 } else if (IS_SMALL_INT(lhs) && IS_SMALL_INT(rhs)) {
696 py_small_int_t val;
697 switch (op) {
698 case RT_BINARY_OP_ADD:
699 case RT_BINARY_OP_INPLACE_ADD: val = FROM_SMALL_INT(lhs) + FROM_SMALL_INT(rhs); break;
700 case RT_BINARY_OP_SUBTRACT: val = FROM_SMALL_INT(lhs) - FROM_SMALL_INT(rhs); break;
701 case RT_BINARY_OP_MULTIPLY: val = FROM_SMALL_INT(lhs) * FROM_SMALL_INT(rhs); break;
702 case RT_BINARY_OP_FLOOR_DIVIDE: val = FROM_SMALL_INT(lhs) / FROM_SMALL_INT(rhs); break;
703#ifdef PY_FLOAT
704 case RT_BINARY_OP_TRUE_DIVIDE: return py_obj_new_float((float_t)FROM_SMALL_INT(lhs) / (float_t)FROM_SMALL_INT(rhs));
705#endif
706 default: printf("%d\n", op); assert(0); val = 0;
707 }
708 if (fit_small_int(val)) {
709 return TO_SMALL_INT(val);
710 }
711 } else if (IS_O(lhs, O_STR) && IS_O(rhs, O_STR)) {
712 const char *lhs_str = qstr_str(((py_obj_base_t*)lhs)->u_str);
713 const char *rhs_str = qstr_str(((py_obj_base_t*)rhs)->u_str);
714 char *val;
715 switch (op) {
716 case RT_BINARY_OP_ADD:
717 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;
718 default: printf("%d\n", op); assert(0); val = NULL;
719 }
720 return py_obj_new_str(qstr_from_str_take(val));
721 }
722 assert(0);
723 return py_const_none;
724}
725
726py_obj_t rt_compare_op(int op, py_obj_t lhs, py_obj_t rhs) {
727 DEBUG_OP_printf("compare %d %p %p\n", op, lhs, rhs);
728 if (IS_SMALL_INT(lhs) && IS_SMALL_INT(rhs)) {
729 int cmp;
730 switch (op) {
731 case RT_COMPARE_OP_LESS: cmp = FROM_SMALL_INT(lhs) < FROM_SMALL_INT(rhs); break;
732 case RT_COMPARE_OP_MORE: cmp = FROM_SMALL_INT(lhs) > FROM_SMALL_INT(rhs); break;
733 default: assert(0); cmp = 0;
734 }
735 if (cmp) {
736 return py_const_true;
737 } else {
738 return py_const_false;
739 }
740 }
741 assert(0);
742 return py_const_none;
743}
744
745py_obj_t rt_make_function_from_id(int unique_code_id) {
Damienb05d7072013-10-05 13:37:10 +0100746 DEBUG_OP_printf("make_function_from_id %d\n", unique_code_id);
747 if (unique_code_id < 1 || unique_code_id >= next_unique_code_id) {
Damien429d7192013-10-04 19:53:11 +0100748 // illegal code id
749 return py_const_none;
750 }
751 py_code_t *c = &unique_codes[unique_code_id];
752 py_obj_base_t *o = m_new(py_obj_base_t, 1);
753 switch (c->kind) {
Damien826005c2013-10-05 23:17:28 +0100754 case PY_CODE_BYTE:
755 o->kind = O_FUN_BC;
756 o->u_fun_bc.n_args = c->n_args;
757 o->u_fun_bc.code = c->u_byte.code;
758 o->u_fun_bc.len = c->u_byte.len;
759 break;
Damien429d7192013-10-04 19:53:11 +0100760 case PY_CODE_NATIVE:
761 switch (c->n_args) {
762 case 0: o->kind = O_FUN_0; break;
763 case 1: o->kind = O_FUN_1; break;
764 case 2: o->kind = O_FUN_2; break;
765 default: assert(0);
766 }
767 o->u_fun.fun = c->u_native.fun;
768 break;
Damien826005c2013-10-05 23:17:28 +0100769 case PY_CODE_INLINE_ASM:
770 o->kind = O_FUN_ASM;
771 o->u_fun_asm.n_args = c->n_args;
772 o->u_fun_asm.fun = c->u_inline_asm.fun;
Damien429d7192013-10-04 19:53:11 +0100773 break;
774 default:
775 assert(0);
776 }
777 return o;
778}
779
780py_obj_t rt_make_function_0(py_fun_0_t fun) {
781 py_obj_base_t *o = m_new(py_obj_base_t, 1);
782 o->kind = O_FUN_0;
783 o->u_fun.fun = fun;
784 return o;
785}
786
787py_obj_t rt_make_function_1(py_fun_1_t fun) {
788 py_obj_base_t *o = m_new(py_obj_base_t, 1);
789 o->kind = O_FUN_1;
790 o->u_fun.fun = fun;
791 return o;
792}
793
794py_obj_t rt_make_function_2(py_fun_2_t fun) {
795 py_obj_base_t *o = m_new(py_obj_base_t, 1);
796 o->kind = O_FUN_2;
797 o->u_fun.fun = fun;
798 return o;
799}
800
801py_obj_t rt_make_function(int n_args, py_fun_t code) {
802 // assumes code is a pointer to a py_fun_t (i think this is safe...)
803 py_obj_base_t *o = m_new(py_obj_base_t, 1);
804 o->kind = O_FUN_N;
Damien429d7192013-10-04 19:53:11 +0100805 o->u_fun.n_args = n_args;
Damien826005c2013-10-05 23:17:28 +0100806 o->u_fun.fun = code;
Damien429d7192013-10-04 19:53:11 +0100807 return o;
808}
809
Damiene4af64f2013-10-06 12:04:13 +0100810// convert a Python object to a sensible value for inline asm
811machine_uint_t rt_convert_obj_for_inline_asm(py_obj_t obj) {
812 // TODO for byte_array, pass pointer to the array
813 if (IS_SMALL_INT(obj)) {
814 return FROM_SMALL_INT(obj);
815 } else if (obj == py_const_none) {
816 return 0;
817 } else if (obj == py_const_false) {
818 return 0;
819 } else if (obj == py_const_true) {
820 return 1;
821 } else {
822 py_obj_base_t *o = obj;
823 switch (o->kind) {
824 case O_STR:
825 // pointer to the string (it's probably constant though!)
826 return (machine_uint_t)qstr_str(o->u_str);
827
828 case O_FLOAT:
829 // convert float to int (could also pass in float registers)
830 return (machine_int_t)o->u_flt;
831
832 case O_LIST:
833 // pointer to start of list (could pass length, but then could use len(x) for that)
834 return (machine_uint_t)o->u_list.items;
835
836 default:
837 // just pass along a pointer to the object
838 return (machine_uint_t)obj;
839 }
840 }
841}
842
843// convert a return value from inline asm to a sensible Python object
844py_obj_t rt_convert_val_from_inline_asm(machine_uint_t val) {
845 return TO_SMALL_INT(val);
846}
847
848typedef machine_uint_t (*inline_asm_fun_0_t)();
849typedef machine_uint_t (*inline_asm_fun_1_t)(machine_uint_t);
850typedef machine_uint_t (*inline_asm_fun_2_t)(machine_uint_t, machine_uint_t);
851
Damien429d7192013-10-04 19:53:11 +0100852py_obj_t rt_call_function_0(py_obj_t fun) {
853 if (IS_O(fun, O_FUN_0)) {
854 py_obj_base_t *o = fun;
Damiene4af64f2013-10-06 12:04:13 +0100855 DEBUG_OP_printf("calling native %p with no args\n", o->u_fun.fun);
Damien429d7192013-10-04 19:53:11 +0100856 return ((py_fun_0_t)o->u_fun.fun)();
857 } else if (IS_O(fun, O_FUN_BC)) {
858 py_obj_base_t *o = fun;
859 assert(o->u_fun_bc.n_args == 0);
Damiene4af64f2013-10-06 12:04:13 +0100860 DEBUG_OP_printf("calling byte code %p with no args\n", o->u_fun_bc.code);
Damien429d7192013-10-04 19:53:11 +0100861 return py_execute_byte_code(o->u_fun_bc.code, o->u_fun_bc.len, NULL, 0);
Damiene4af64f2013-10-06 12:04:13 +0100862 } else if (IS_O(fun, O_FUN_ASM)) {
863 py_obj_base_t *o = fun;
864 assert(o->u_fun_asm.n_args == 0);
865 DEBUG_OP_printf("calling inline asm %p with no args\n", o->u_fun_asm.fun);
866 return rt_convert_val_from_inline_asm(((inline_asm_fun_0_t)o->u_fun_asm.fun)());
Damiena3977762013-10-09 23:10:10 +0100867 } else if (IS_O(fun, O_BOUND_METH)) {
868 py_obj_base_t *o = fun;
869 DEBUG_OP_printf("calling bound method %p with self and no args\n", o->u_bound_meth.meth);
870 return rt_call_function_1(o->u_bound_meth.meth, o->u_bound_meth.self);
871 } else if (IS_O(fun, O_CLASS)) {
872 // instantiate an instance of a class
873 DEBUG_OP_printf("instantiate object of class %p with no args\n", fun);
874 py_obj_base_t *o = m_new(py_obj_base_t, 1);
875 o->kind = O_OBJ;
876 o->u_obj.class = fun;
877 o->u_obj.members = py_map_new(MAP_QSTR, 0);
878 return o;
Damien429d7192013-10-04 19:53:11 +0100879 } else {
880 printf("fun0:%p\n", fun);
881 assert(0);
882 return py_const_none;
883 }
884}
885
886py_obj_t rt_call_function_1(py_obj_t fun, py_obj_t arg) {
887 if (IS_O(fun, O_FUN_1)) {
888 py_obj_base_t *o = fun;
Damien6cdd3af2013-10-05 18:08:26 +0100889 DEBUG_OP_printf("calling native %p with 1 arg\n", o->u_fun.fun);
Damien429d7192013-10-04 19:53:11 +0100890 return ((py_fun_1_t)o->u_fun.fun)(arg);
891 } else if (IS_O(fun, O_FUN_BC)) {
892 py_obj_base_t *o = fun;
Damiena3977762013-10-09 23:10:10 +0100893 if (o->u_fun_bc.n_args != 1) {
894 printf("rt_call_function_1: trying to pass 1 argument to a function that takes %d arguments\n", o->u_fun_bc.n_args);
895 assert(0);
896 }
Damien6cdd3af2013-10-05 18:08:26 +0100897 DEBUG_OP_printf("calling byte code %p with 1 arg\n", o->u_fun_bc.code);
Damien429d7192013-10-04 19:53:11 +0100898 return py_execute_byte_code(o->u_fun_bc.code, o->u_fun_bc.len, &arg, 1);
Damiendc833822013-10-06 01:01:01 +0100899 } else if (IS_O(fun, O_FUN_ASM)) {
900 py_obj_base_t *o = fun;
901 assert(o->u_fun_asm.n_args == 1);
902 DEBUG_OP_printf("calling inline asm %p with 1 arg\n", o->u_fun_asm.fun);
Damiene4af64f2013-10-06 12:04:13 +0100903 return rt_convert_val_from_inline_asm(((inline_asm_fun_1_t)o->u_fun_asm.fun)(rt_convert_obj_for_inline_asm(arg)));
Damien429d7192013-10-04 19:53:11 +0100904 } else if (IS_O(fun, O_BOUND_METH)) {
905 py_obj_base_t *o = fun;
906 return rt_call_function_2(o->u_bound_meth.meth, o->u_bound_meth.self, arg);
907 } else {
908 printf("fun1:%p\n", fun);
909 assert(0);
910 return py_const_none;
911 }
912}
913
914py_obj_t rt_call_function_2(py_obj_t fun, py_obj_t arg1, py_obj_t arg2) {
915 if (IS_O(fun, O_FUN_2)) {
916 py_obj_base_t *o = fun;
Damiene4af64f2013-10-06 12:04:13 +0100917 DEBUG_OP_printf("calling native %p with 2 args\n", o->u_fun.fun);
Damien429d7192013-10-04 19:53:11 +0100918 return ((py_fun_2_t)o->u_fun.fun)(arg1, arg2);
919 } else if (IS_O(fun, O_FUN_BC)) {
920 py_obj_base_t *o = fun;
921 assert(o->u_fun_bc.n_args == 2);
Damiene4af64f2013-10-06 12:04:13 +0100922 DEBUG_OP_printf("calling byte code %p with 2 args\n", o->u_fun_bc.code);
Damien429d7192013-10-04 19:53:11 +0100923 py_obj_t args[2];
Damiena3977762013-10-09 23:10:10 +0100924 args[1] = arg1;
925 args[0] = arg2;
Damien429d7192013-10-04 19:53:11 +0100926 return py_execute_byte_code(o->u_fun_bc.code, o->u_fun_bc.len, &args[0], 2);
Damiene4af64f2013-10-06 12:04:13 +0100927 } else if (IS_O(fun, O_FUN_ASM)) {
928 py_obj_base_t *o = fun;
929 assert(o->u_fun_asm.n_args == 2);
930 DEBUG_OP_printf("calling inline asm %p with 2 args\n", o->u_fun_asm.fun);
931 return rt_convert_val_from_inline_asm(((inline_asm_fun_2_t)o->u_fun_asm.fun)(rt_convert_obj_for_inline_asm(arg1), rt_convert_obj_for_inline_asm(arg2)));
Damien429d7192013-10-04 19:53:11 +0100932 } else {
933 assert(0);
934 return py_const_none;
935 }
936}
937
Damiena3977762013-10-09 23:10:10 +0100938// args are in reverse order in the array
939py_obj_t rt_call_function_n(py_obj_t fun, int n_args, const py_obj_t *args) {
940 if (IS_O(fun, O_FUN_BC)) {
941 py_obj_base_t *o = fun;
942 assert(o->u_fun_bc.n_args == n_args);
943 DEBUG_OP_printf("calling byte code %p with %d args\n", o->u_fun_bc.code, n_args);
944 return py_execute_byte_code(o->u_fun_bc.code, o->u_fun_bc.len, args, n_args);
945 } else {
946 assert(0);
947 return py_const_none;
948 }
949}
950
Damien429d7192013-10-04 19:53:11 +0100951py_obj_t rt_call_method_1(py_obj_t fun, py_obj_t self) {
952 DEBUG_OP_printf("call method %p %p\n", fun, self);
953 if (self == NULL) {
954 return rt_call_function_0(fun);
955 } else {
956 return rt_call_function_1(fun, self);
957 }
958}
959
960py_obj_t rt_call_method_2(py_obj_t fun, py_obj_t self, py_obj_t arg) {
961 DEBUG_OP_printf("call method %p %p %p\n", fun, self, arg);
962 if (self == NULL) {
963 return rt_call_function_1(fun, arg);
964 } else {
965 return rt_call_function_2(fun, self, arg);
966 }
967}
968
Damiena3977762013-10-09 23:10:10 +0100969// args contains: arg(n_args-1) arg(n_args-2) ... arg(0) self/NULL fun
970// if n_args==0 then there are only self/NULL and fun
971py_obj_t rt_call_method_n(int n_args, const py_obj_t *args) {
972 DEBUG_OP_printf("call method %p %p %d args\n", args[n_args + 1], args[n_args] , n_args);
973 return rt_call_function_n(args[n_args + 1], n_args + ((args[n_args] == NULL) ? 0 : 1), args);
974}
975
Damien429d7192013-10-04 19:53:11 +0100976// items are in reverse order
977py_obj_t rt_build_list(int n_args, py_obj_t *items) {
978 py_obj_base_t *o = m_new(py_obj_base_t, 1);
979 o->kind = O_LIST;
980 o->u_list.alloc = n_args;
981 if (o->u_list.alloc < 4) {
982 o->u_list.alloc = 4;
983 }
984 o->u_list.len = n_args;
985 o->u_list.items = m_new(py_obj_t, o->u_list.alloc);
986 for (int i = 0; i < n_args; i++) {
987 o->u_list.items[i] = items[n_args - i - 1];
988 }
989 return o;
990}
991
992py_obj_t py_set_lookup(py_obj_t o_in, py_obj_t index, bool add_if_not_found) {
993 assert(IS_O(o_in, O_SET));
994 py_obj_base_t *o = o_in;
995 int hash = py_obj_hash(index);
996 int pos = hash % o->u_set.alloc;
997 for (;;) {
998 py_obj_t elem = o->u_set.table[pos];
999 if (elem == NULL) {
1000 // not in table
1001 if (add_if_not_found) {
1002 if (o->u_set.used + 1 >= o->u_set.alloc) {
1003 // not enough room in table, rehash it
1004 int old_alloc = o->u_set.alloc;
1005 py_obj_t *old_table = o->u_set.table;
1006 o->u_set.alloc = get_doubling_prime_greater_or_equal_to(o->u_set.alloc + 1);
1007 o->u_set.used = 0;
1008 o->u_set.table = m_new(py_obj_t, o->u_set.alloc);
1009 for (int i = 0; i < old_alloc; i++) {
1010 if (old_table[i] != NULL) {
1011 py_set_lookup(o, old_table[i], true);
1012 }
1013 }
1014 m_free(old_table);
1015 // restart the search for the new element
1016 pos = hash % o->u_set.alloc;
1017 } else {
1018 o->u_set.used += 1;
1019 o->u_set.table[pos] = index;
1020 return index;
1021 }
1022 } else {
1023 return NULL;
1024 }
1025 } else if (py_obj_equal(elem, index)) {
1026 // found it
1027 return elem;
1028 } else {
1029 // not yet found, keep searching in this table
1030 pos = (pos + 1) % o->u_set.alloc;
1031 }
1032 }
1033}
1034
1035py_obj_t rt_build_set(int n_args, py_obj_t *items) {
1036 py_obj_base_t *o = m_new(py_obj_base_t, 1);
1037 o->kind = O_SET;
1038 o->u_set.alloc = get_doubling_prime_greater_or_equal_to(n_args + 1);
1039 o->u_set.used = 0;
1040 o->u_set.table = m_new(py_obj_t, o->u_set.alloc);
1041 for (int i = 0; i < o->u_set.alloc; i++) {
1042 o->u_set.table[i] = NULL;
1043 }
1044 for (int i = 0; i < n_args; i++) {
1045 py_set_lookup(o, items[i], true);
1046 }
1047 return o;
1048}
1049
1050py_obj_t rt_build_map(int n_args) {
1051 py_obj_base_t *o = m_new(py_obj_base_t, 1);
1052 o->kind = O_MAP;
1053 py_map_init(&o->u_map, MAP_PY_OBJ, n_args);
1054 return o;
1055}
1056
1057py_obj_t rt_store_map(py_obj_t map, py_obj_t key, py_obj_t value) {
1058 assert(IS_O(map, O_MAP)); // should always be
1059 py_map_lookup(map, key, true)->value = value;
1060 return map;
1061}
1062
Damiena3977762013-10-09 23:10:10 +01001063py_obj_t build_bound_method(py_obj_t self, py_obj_t meth) {
1064 py_obj_base_t *o = m_new(py_obj_base_t, 1);
1065 o->kind = O_BOUND_METH;
1066 o->u_bound_meth.meth = meth;
1067 o->u_bound_meth.self = self;
1068 return o;
1069}
1070
1071py_obj_t rt_load_attr(py_obj_t base, qstr attr) {
1072 DEBUG_OP_printf("load attr %s\n", qstr_str(attr));
1073 if (IS_O(base, O_LIST) && attr == q_append) {
1074 return build_bound_method(base, fun_list_append);
1075 } else if (IS_O(base, O_CLASS)) {
1076 py_obj_base_t *o = base;
1077 py_map_elem_t *elem = py_qstr_map_lookup(o->u_class.locals, attr, false);
1078 if (elem == NULL) {
1079 goto no_attr;
1080 }
1081 return elem->value;
1082 } else if (IS_O(base, O_OBJ)) {
1083 // logic: look in obj members then class locals (TODO check this against CPython)
1084 py_obj_base_t *o = base;
1085 py_map_elem_t *elem = py_qstr_map_lookup(o->u_obj.members, attr, false);
1086 if (elem != NULL) {
1087 // object member, always treated as a value
1088 return elem->value;
1089 }
1090 elem = py_qstr_map_lookup(o->u_obj.class->u_class.locals, attr, false);
1091 if (elem != NULL) {
1092 if (py_obj_is_callable(elem->value)) {
1093 // class member is callable so build a bound method
1094 return build_bound_method(base, elem->value);
1095 } else {
1096 // class member is a value, so just return that value
1097 return elem->value;
1098 }
1099 }
1100 goto no_attr;
1101 }
1102
1103no_attr:
1104 printf("AttributeError: '%s' object has no attribute '%s'\n", py_obj_get_type_str(base), qstr_str(attr));
1105 assert(0);
1106 return py_const_none;
1107}
1108
1109void rt_load_method(py_obj_t base, qstr attr, py_obj_t *dest) {
1110 DEBUG_OP_printf("load method %s\n", qstr_str(attr));
1111 if (IS_O(base, O_LIST) && attr == q_append) {
1112 dest[1] = fun_list_append;
1113 dest[0] = base;
1114 return;
1115 } else if (IS_O(base, O_OBJ)) {
1116 // logic: look in obj members then class locals (TODO check this against CPython)
1117 py_obj_base_t *o = base;
1118 py_map_elem_t *elem = py_qstr_map_lookup(o->u_obj.members, attr, false);
1119 if (elem != NULL) {
1120 // object member, always treated as a value
1121 dest[1] = elem->value;
1122 dest[0] = NULL;
1123 return;
1124 }
1125 elem = py_qstr_map_lookup(o->u_obj.class->u_class.locals, attr, false);
1126 if (elem != NULL) {
1127 if (py_obj_is_callable(elem->value)) {
1128 // class member is callable so build a bound method
1129 dest[1] = elem->value;
1130 dest[0] = base;
1131 return;
1132 } else {
1133 // class member is a value, so just return that value
1134 dest[1] = elem->value;
1135 dest[0] = NULL;
1136 return;
1137 }
1138 }
1139 goto no_attr;
1140 }
1141
1142no_attr:
1143 dest[1] = rt_load_attr(base, attr);
1144 dest[0] = NULL;
1145}
1146
1147void rt_store_attr(py_obj_t base, qstr attr, py_obj_t val) {
1148 DEBUG_OP_printf("store attr %p.%s <- %p\n", base, qstr_str(attr), val);
1149 if (IS_O(base, O_OBJ)) {
1150 // logic: look in class locals (no add) then obj members (add) (TODO check this against CPython)
1151 py_obj_base_t *o = base;
1152 py_map_elem_t *elem = py_qstr_map_lookup(o->u_obj.class->u_class.locals, attr, false);
1153 if (elem != NULL) {
1154 elem->value = val;
1155 } else {
1156 elem = py_qstr_map_lookup(o->u_obj.class->u_class.locals, attr, true)->value = val;
1157 }
1158 } else {
1159 printf("?AttributeError: '%s' object has no attribute '%s'\n", py_obj_get_type_str(base), qstr_str(attr));
1160 assert(0);
1161 }
1162}
1163
Damien429d7192013-10-04 19:53:11 +01001164void rt_store_subscr(py_obj_t base, py_obj_t index, py_obj_t value) {
1165 if (IS_O(base, O_LIST) && IS_SMALL_INT(index)) {
1166 // list store
1167 py_obj_base_t *o = base;
1168 int idx = FROM_SMALL_INT(index);
1169 if (idx < 0) {
1170 idx += o->u_list.len;
1171 }
1172 if (0 <= idx && idx < o->u_list.len) {
1173 o->u_list.items[idx] = value;
1174 } else {
1175 assert(0);
1176 }
1177 } else if (IS_O(base, O_MAP)) {
1178 // map store
1179 py_map_lookup(base, index, true)->value = value;
1180 } else {
1181 assert(0);
1182 }
1183}
1184
Damien429d7192013-10-04 19:53:11 +01001185void *rt_fun_table[RT_F_NUMBER_OF] = {
1186 rt_load_const_str,
1187 rt_load_name,
1188 rt_load_global,
1189 rt_load_attr,
1190 rt_load_method,
1191 rt_store_name,
1192 rt_store_subscr,
1193 rt_is_true,
1194 rt_unary_op,
1195 rt_build_list,
1196 rt_build_map,
1197 rt_store_map,
1198 rt_build_set,
1199 rt_make_function_from_id,
1200 rt_call_function_0,
1201 rt_call_function_1,
1202 rt_call_function_2,
1203 rt_call_method_1,
1204 rt_call_method_2,
1205 rt_binary_op,
1206 rt_compare_op,
1207};
1208
1209/*
1210void rt_f_vector(rt_fun_kind_t fun_kind) {
1211 (rt_f_table[fun_kind])();
1212}
1213*/