blob: 958507521fc2a566b8c48d3ffd8b9bc821863e2b [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"
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
22// enable/disable float support with this definition
23#define PY_FLOAT (1)
24
25typedef machine_int_t py_small_int_t;
26
27#define IS_O(o, k) (((((py_small_int_t)(o)) & 1) == 0) && (((py_obj_base_t*)(o))->kind == (k)))
28#define IS_SMALL_INT(o) (((py_small_int_t)(o)) & 1)
29#define FROM_SMALL_INT(o) (((py_small_int_t)(o)) >> 1)
30#define TO_SMALL_INT(o) ((py_obj_t)(((o) << 1) | 1))
31
32#ifdef PY_FLOAT
33typedef machine_float_t float_t;
34#endif
35
36typedef enum {
37 O_CONST,
38 O_STR,
39#ifdef PY_FLOAT
40 O_FLOAT,
41#endif
42 O_FUN_0,
43 O_FUN_1,
44 O_FUN_2,
45 O_FUN_N,
46 O_FUN_BC,
Damien826005c2013-10-05 23:17:28 +010047 O_FUN_ASM,
Damien429d7192013-10-04 19:53:11 +010048 O_BOUND_METH,
49 O_LIST,
50 O_SET,
51 O_MAP,
52 O_CLASS,
Damiena3977762013-10-09 23:10:10 +010053 O_OBJ,
Damien429d7192013-10-04 19:53:11 +010054} py_obj_kind_t;
55
56typedef enum {
57 MAP_QSTR,
58 MAP_PY_OBJ,
59} py_map_kind_t;
60
61typedef struct _py_map_elem_t {
62 py_obj_t key;
63 py_obj_t value;
64} py_map_elem_t;
65
66typedef struct _py_map_t {
Damiena3977762013-10-09 23:10:10 +010067 py_map_kind_t kind; // TODO merge this 1-bit field into alloc or used
Damien429d7192013-10-04 19:53:11 +010068 machine_uint_t alloc;
69 machine_uint_t used;
70 py_map_elem_t *table;
71} py_map_t;
72
Damiena3977762013-10-09 23:10:10 +010073typedef struct _py_obj_base_t py_obj_base_t;
74
75struct _py_obj_base_t {
Damien429d7192013-10-04 19:53:11 +010076 py_obj_kind_t kind;
77 union {
78 const char *id;
79 qstr u_str;
80#ifdef PY_FLOAT
Damiene4af64f2013-10-06 12:04:13 +010081 float_t u_flt;
Damien429d7192013-10-04 19:53:11 +010082#endif
83 struct { // for O_FUN_[012N]
Damien429d7192013-10-04 19:53:11 +010084 int n_args;
Damien826005c2013-10-05 23:17:28 +010085 void *fun;
Damien429d7192013-10-04 19:53:11 +010086 } u_fun;
87 struct { // for O_FUN_BC
Damien826005c2013-10-05 23:17:28 +010088 int n_args;
Damien429d7192013-10-04 19:53:11 +010089 byte *code;
90 uint len;
Damien429d7192013-10-04 19:53:11 +010091 } u_fun_bc;
Damien826005c2013-10-05 23:17:28 +010092 struct { // for O_FUN_ASM
93 int n_args;
94 void *fun;
95 } u_fun_asm;
Damien429d7192013-10-04 19:53:11 +010096 struct { // for O_BOUND_METH
97 py_obj_t meth;
98 py_obj_t self;
99 } u_bound_meth;
100 struct { // for O_LIST
101 int alloc;
102 int len;
103 py_obj_t *items;
104 } u_list;
105 struct { // for O_SET
106 int alloc;
107 int used;
108 py_obj_t *table;
109 } u_set;
110 py_map_t u_map; // for O_MAP
Damien429d7192013-10-04 19:53:11 +0100111 struct { // for O_CLASS
Damiena3977762013-10-09 23:10:10 +0100112 py_map_t *locals;
Damien429d7192013-10-04 19:53:11 +0100113 } u_class;
Damiena3977762013-10-09 23:10:10 +0100114 struct { // for O_OBJ
115 py_obj_base_t *class; // points to a O_CLASS object
116 py_map_t *members;
117 } u_obj;
Damien429d7192013-10-04 19:53:11 +0100118 };
Damiena3977762013-10-09 23:10:10 +0100119};
Damien429d7192013-10-04 19:53:11 +0100120
121py_obj_t py_const_none;
122py_obj_t py_const_false;
123py_obj_t py_const_true;
124
Damieneb19efb2013-10-10 22:06:54 +0100125// locals and globals need to be pointers because they can be the same in outer module scope
126py_map_t *map_locals;
127py_map_t *map_globals;
Damien429d7192013-10-04 19:53:11 +0100128py_map_t map_builtins;
129
130// approximatelly doubling primes; made with Mathematica command: Table[Prime[Floor[(1.7)^n]], {n, 3, 24}]
131static 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};
132
133int get_doubling_prime_greater_or_equal_to(int x) {
134 for (int i = 0; i < sizeof(doubling_primes) / sizeof(int); i++) {
135 if (doubling_primes[i] >= x) {
136 return doubling_primes[i];
137 }
138 }
139 // ran out of primes in the table!
140 // return something sensible, at least make it odd
141 return x | 1;
142}
143
144void py_map_init(py_map_t *map, py_map_kind_t kind, int n) {
145 map->kind = kind;
146 map->alloc = get_doubling_prime_greater_or_equal_to(n + 1);
147 map->used = 0;
148 map->table = m_new(py_map_elem_t, map->alloc);
149 for (int i = 0; i < map->alloc; i++) {
150 map->table[i].key = NULL;
151 map->table[i].value = NULL;
152 }
153}
154
155py_map_t *py_map_new(py_map_kind_t kind, int n) {
156 py_map_t *map = m_new(py_map_t, 1);
157 py_map_init(map, kind, n);
158 return map;
159}
160
161int py_obj_hash(py_obj_t o_in) {
162 if (IS_SMALL_INT(o_in)) {
163 return FROM_SMALL_INT(o_in);
164 } else if (IS_O(o_in, O_STR)) {
165 return ((py_obj_base_t*)o_in)->u_str;
166 } else {
167 assert(0);
168 return 0;
169 }
170}
171
172bool py_obj_equal(py_obj_t o1, py_obj_t o2) {
173 if (o1 == o2) {
174 return true;
175 } else if (IS_SMALL_INT(o1) && IS_SMALL_INT(o2)) {
176 return false;
177 } else if (IS_O(o1, O_STR) && IS_O(o2, O_STR)) {
178 return ((py_obj_base_t*)o1)->u_str == ((py_obj_base_t*)o2)->u_str;
179 } else {
180 assert(0);
181 return false;
182 }
183}
184
185py_map_elem_t* py_map_lookup_helper(py_map_t *map, py_obj_t index, bool add_if_not_found) {
186 bool is_map_py_obj = (map->kind == MAP_PY_OBJ);
187 machine_uint_t hash;
188 if (is_map_py_obj) {
189 hash = py_obj_hash(index);
190 } else {
191 hash = (machine_uint_t)index;
192 }
193 uint pos = hash % map->alloc;
194 for (;;) {
195 py_map_elem_t *elem = &map->table[pos];
196 if (elem->key == NULL) {
197 // not in table
198 if (add_if_not_found) {
199 if (map->used + 1 >= map->alloc) {
200 // not enough room in table, rehash it
201 int old_alloc = map->alloc;
202 py_map_elem_t *old_table = map->table;
203 map->alloc = get_doubling_prime_greater_or_equal_to(map->alloc + 1);
204 map->used = 0;
205 map->table = m_new(py_map_elem_t, map->alloc);
206 for (int i = 0; i < old_alloc; i++) {
207 if (old_table[i].key != NULL) {
208 py_map_lookup_helper(map, old_table[i].key, true)->value = old_table[i].value;
209 }
210 }
211 m_free(old_table);
212 // restart the search for the new element
213 pos = hash % map->alloc;
214 } else {
215 map->used += 1;
216 elem->key = index;
217 return elem;
218 }
219 } else {
220 return NULL;
221 }
222 } else if (elem->key == index || (is_map_py_obj && py_obj_equal(elem->key, index))) {
223 // found it
224 if (add_if_not_found) {
225 elem->key = index;
226 }
227 return elem;
228 } else {
229 // not yet found, keep searching in this table
230 pos = (pos + 1) % map->alloc;
231 }
232 }
233}
234
235py_map_elem_t* py_qstr_map_lookup(py_map_t *map, qstr index, bool add_if_not_found) {
236 py_obj_t o = (py_obj_t)(machine_uint_t)index;
237 return py_map_lookup_helper(map, o, add_if_not_found);
238}
239
240py_map_elem_t* py_map_lookup(py_obj_t o, py_obj_t index, bool add_if_not_found) {
241 assert(IS_O(o, O_MAP));
242 return py_map_lookup_helper(&((py_obj_base_t *)o)->u_map, index, add_if_not_found);
243}
244
245static bool fit_small_int(py_small_int_t o) {
246 return true;
247}
248
249py_obj_t py_obj_new_const(const char *id) {
250 py_obj_base_t *o = m_new(py_obj_base_t, 1);
251 o->kind = O_CONST;
252 o->id = id;
253 return (py_obj_t)o;
254}
255
256py_obj_t py_obj_new_str(qstr qstr) {
257 py_obj_base_t *o = m_new(py_obj_base_t, 1);
258 o->kind = O_STR;
259 o->u_str = qstr;
260 return (py_obj_t)o;
261}
262
263#ifdef PY_FLOAT
264py_obj_t py_obj_new_float(float_t val) {
265 py_obj_base_t *o = m_new(py_obj_base_t, 1);
266 o->kind = O_FLOAT;
Damiene4af64f2013-10-06 12:04:13 +0100267 o->u_flt = val;
Damien429d7192013-10-04 19:53:11 +0100268 return (py_obj_t)o;
269}
270#endif
271
272py_obj_t list_append(py_obj_t self_in, py_obj_t arg) {
273 assert(IS_O(self_in, O_LIST));
274 py_obj_base_t *self = self_in;
275 if (self->u_list.len >= self->u_list.alloc) {
276 self->u_list.alloc *= 2;
277 self->u_list.items = m_renew(py_obj_t, self->u_list.items, self->u_list.alloc);
278 }
279 self->u_list.items[self->u_list.len++] = arg;
280 return arg;
281}
282
283static qstr q_append;
284static qstr q_print;
285static qstr q_len;
286static qstr q___build_class__;
287
288typedef enum {
Damien826005c2013-10-05 23:17:28 +0100289 PY_CODE_NONE,
Damien429d7192013-10-04 19:53:11 +0100290 PY_CODE_BYTE,
Damien826005c2013-10-05 23:17:28 +0100291 PY_CODE_NATIVE,
292 PY_CODE_INLINE_ASM,
Damien429d7192013-10-04 19:53:11 +0100293} py_code_kind_t;
294
295typedef struct _py_code_t {
296 py_code_kind_t kind;
297 int n_args;
298 union {
299 struct {
Damien429d7192013-10-04 19:53:11 +0100300 byte *code;
301 uint len;
302 } u_byte;
Damien826005c2013-10-05 23:17:28 +0100303 struct {
304 py_fun_t fun;
305 } u_native;
306 struct {
Damiene4af64f2013-10-06 12:04:13 +0100307 void *fun;
Damien826005c2013-10-05 23:17:28 +0100308 } u_inline_asm;
Damien429d7192013-10-04 19:53:11 +0100309 };
310} py_code_t;
311
312static int next_unique_code_id;
313static py_code_t *unique_codes;
314
315py_obj_t fun_list_append;
316
317py_obj_t py_builtin_print(py_obj_t o) {
318 if (IS_O(o, O_STR)) {
319 // special case, print string raw
320 printf("%s\n", qstr_str(((py_obj_base_t*)o)->u_str));
321 } else {
322 // print the object Python style
323 py_obj_print(o);
324 printf("\n");
325 }
326 return py_const_none;
327}
328
329py_obj_t py_builtin_len(py_obj_t o_in) {
330 py_small_int_t len = 0;
331 if (IS_O(o_in, O_LIST)) {
332 py_obj_base_t *o = o_in;
333 len = o->u_list.len;
334 } else if (IS_O(o_in, O_MAP)) {
335 py_obj_base_t *o = o_in;
336 len = o->u_map.used;
337 } else {
338 assert(0);
339 }
340 return TO_SMALL_INT(len);
341}
342
Damiena3977762013-10-09 23:10:10 +0100343py_obj_t py_builtin___build_class__(py_obj_t o_class_fun, py_obj_t o_class_name) {
344 // we differ from CPython: we set the new __locals__ object here
Damieneb19efb2013-10-10 22:06:54 +0100345 py_map_t *old_locals = map_locals;
Damiena3977762013-10-09 23:10:10 +0100346 py_map_t *class_locals = py_map_new(MAP_QSTR, 0);
Damieneb19efb2013-10-10 22:06:54 +0100347 map_locals = class_locals;
Damiena3977762013-10-09 23:10:10 +0100348
349 // call the class code
350 rt_call_function_1(o_class_fun, (py_obj_t)0xdeadbeef);
351
352 // restore old __locals__ object
353 map_locals = old_locals;
354
355 // create and return the new class
Damien429d7192013-10-04 19:53:11 +0100356 py_obj_base_t *o = m_new(py_obj_base_t, 1);
357 o->kind = O_CLASS;
Damiena3977762013-10-09 23:10:10 +0100358 o->u_class.locals = class_locals;
Damien429d7192013-10-04 19:53:11 +0100359 return o;
360}
361
Damiena1ddfcc2013-10-10 23:25:50 +0100362#ifdef WRITE_NATIVE
Damien429d7192013-10-04 19:53:11 +0100363FILE *fp_native = NULL;
Damiena1ddfcc2013-10-10 23:25:50 +0100364#endif
Damien429d7192013-10-04 19:53:11 +0100365
366void rt_init() {
367 q_append = qstr_from_str_static("append");
368 q_print = qstr_from_str_static("print");
369 q_len = qstr_from_str_static("len");
370 q___build_class__ = qstr_from_str_static("__build_class__");
371
372 py_const_none = py_obj_new_const("None");
373 py_const_false = py_obj_new_const("False");
374 py_const_true = py_obj_new_const("True");
375
Damieneb19efb2013-10-10 22:06:54 +0100376 // locals = globals for outer module (see Objects/frameobject.c/PyFrame_New())
377 map_locals = map_globals = py_map_new(MAP_QSTR, 1);
378 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 +0100379
380 py_map_init(&map_builtins, MAP_QSTR, 3);
381 py_qstr_map_lookup(&map_builtins, q_print, true)->value = rt_make_function_1(py_builtin_print);
382 py_qstr_map_lookup(&map_builtins, q_len, true)->value = rt_make_function_1(py_builtin_len);
383 py_qstr_map_lookup(&map_builtins, q___build_class__, true)->value = rt_make_function_2(py_builtin___build_class__);
384
385 next_unique_code_id = 1;
386 unique_codes = NULL;
387
388 fun_list_append = rt_make_function_2(list_append);
389
Damiena1ddfcc2013-10-10 23:25:50 +0100390#ifdef WRITE_NATIVE
Damien429d7192013-10-04 19:53:11 +0100391 fp_native = fopen("out-native", "wb");
Damiena1ddfcc2013-10-10 23:25:50 +0100392#endif
Damien429d7192013-10-04 19:53:11 +0100393}
394
395void rt_deinit() {
Damiena1ddfcc2013-10-10 23:25:50 +0100396#ifdef WRITE_NATIVE
Damien429d7192013-10-04 19:53:11 +0100397 if (fp_native != NULL) {
398 fclose(fp_native);
399 }
Damiena1ddfcc2013-10-10 23:25:50 +0100400#endif
Damien429d7192013-10-04 19:53:11 +0100401}
402
403int rt_get_new_unique_code_id() {
404 return next_unique_code_id++;
405}
406
Damien826005c2013-10-05 23:17:28 +0100407static void alloc_unique_codes() {
Damien429d7192013-10-04 19:53:11 +0100408 if (unique_codes == NULL) {
409 unique_codes = m_new(py_code_t, next_unique_code_id);
Damien826005c2013-10-05 23:17:28 +0100410 for (int i = 0; i < next_unique_code_id; i++) {
411 unique_codes[i].kind = PY_CODE_NONE;
412 }
Damien429d7192013-10-04 19:53:11 +0100413 }
Damien826005c2013-10-05 23:17:28 +0100414}
415
416void rt_assign_byte_code(int unique_code_id, byte *code, uint len, int n_args) {
417 alloc_unique_codes();
418
419 assert(unique_code_id < next_unique_code_id);
420 unique_codes[unique_code_id].kind = PY_CODE_BYTE;
421 unique_codes[unique_code_id].n_args = n_args;
422 unique_codes[unique_code_id].u_byte.code = code;
423 unique_codes[unique_code_id].u_byte.len = len;
424
425 DEBUG_printf("assign byte code: id=%d code=%p len=%u n_args=%d\n", unique_code_id, code, len, n_args);
426}
427
428void rt_assign_native_code(int unique_code_id, py_fun_t fun, uint len, int n_args) {
429 alloc_unique_codes();
430
Damienb05d7072013-10-05 13:37:10 +0100431 assert(1 <= unique_code_id && unique_code_id < next_unique_code_id);
Damien429d7192013-10-04 19:53:11 +0100432 unique_codes[unique_code_id].kind = PY_CODE_NATIVE;
433 unique_codes[unique_code_id].n_args = n_args;
434 unique_codes[unique_code_id].u_native.fun = fun;
435
Damiena1ddfcc2013-10-10 23:25:50 +0100436#ifdef DEBUG_PRINT
Damien429d7192013-10-04 19:53:11 +0100437 DEBUG_printf("assign native code: id=%d fun=%p len=%u n_args=%d\n", unique_code_id, fun, len, n_args);
438 byte *fun_data = (byte*)(((machine_uint_t)fun) & (~1)); // need to clear lower bit in case it's thumb code
439 for (int i = 0; i < 128 && i < len; i++) {
440 if (i > 0 && i % 16 == 0) {
441 DEBUG_printf("\n");
442 }
443 DEBUG_printf(" %02x", fun_data[i]);
444 }
445 DEBUG_printf("\n");
446
Damiena1ddfcc2013-10-10 23:25:50 +0100447#ifdef WRITE_NATIVE
Damien429d7192013-10-04 19:53:11 +0100448 if (fp_native != NULL) {
449 fwrite(fun_data, len, 1, fp_native);
Damien13ed3a62013-10-08 09:05:10 +0100450 fflush(fp_native);
Damien429d7192013-10-04 19:53:11 +0100451 }
Damiena1ddfcc2013-10-10 23:25:50 +0100452#endif
453#endif
Damien429d7192013-10-04 19:53:11 +0100454}
455
Damien826005c2013-10-05 23:17:28 +0100456void rt_assign_inline_asm_code(int unique_code_id, py_fun_t fun, uint len, int n_args) {
457 alloc_unique_codes();
Damien429d7192013-10-04 19:53:11 +0100458
Damien826005c2013-10-05 23:17:28 +0100459 assert(1 <= unique_code_id && unique_code_id < next_unique_code_id);
460 unique_codes[unique_code_id].kind = PY_CODE_INLINE_ASM;
461 unique_codes[unique_code_id].n_args = n_args;
462 unique_codes[unique_code_id].u_inline_asm.fun = fun;
463
Damiena1ddfcc2013-10-10 23:25:50 +0100464#ifdef DEBUG_PRINT
Damien826005c2013-10-05 23:17:28 +0100465 DEBUG_printf("assign inline asm code: id=%d fun=%p len=%u n_args=%d\n", unique_code_id, fun, len, n_args);
466 byte *fun_data = (byte*)(((machine_uint_t)fun) & (~1)); // need to clear lower bit in case it's thumb code
467 for (int i = 0; i < 128 && i < len; i++) {
468 if (i > 0 && i % 16 == 0) {
469 DEBUG_printf("\n");
470 }
471 DEBUG_printf(" %02x", fun_data[i]);
472 }
473 DEBUG_printf("\n");
474
Damiena1ddfcc2013-10-10 23:25:50 +0100475#ifdef WRITE_NATIVE
Damien826005c2013-10-05 23:17:28 +0100476 if (fp_native != NULL) {
477 fwrite(fun_data, len, 1, fp_native);
478 }
Damiena1ddfcc2013-10-10 23:25:50 +0100479#endif
480#endif
Damien429d7192013-10-04 19:53:11 +0100481}
482
Damiena3977762013-10-09 23:10:10 +0100483bool py_obj_is_callable(py_obj_t o_in) {
484 if (IS_SMALL_INT(o_in)) {
485 return false;
486 } else {
487 py_obj_base_t *o = o_in;
488 switch (o->kind) {
489 case O_FUN_0:
490 case O_FUN_1:
491 case O_FUN_2:
492 case O_FUN_N:
493 case O_FUN_BC:
494 case O_FUN_ASM:
Damieneb19efb2013-10-10 22:06:54 +0100495 // what about O_CLASS, and an O_OBJ that has a __call__ method?
Damiena3977762013-10-09 23:10:10 +0100496 return true;
497 default:
498 return false;
499 }
500 }
501}
502
Damien429d7192013-10-04 19:53:11 +0100503const char *py_obj_get_type_str(py_obj_t o_in) {
504 if (IS_SMALL_INT(o_in)) {
505 return "int";
506 } else {
507 py_obj_base_t *o = o_in;
508 switch (o->kind) {
509 case O_CONST:
510 if (o == py_const_none) {
511 return "NoneType";
512 } else {
513 return "bool";
514 }
515 case O_STR:
516 return "str";
517#ifdef PY_FLOAT
518 case O_FLOAT:
519 return "float";
520#endif
Damien6cdd3af2013-10-05 18:08:26 +0100521 case O_FUN_0:
522 case O_FUN_1:
523 case O_FUN_2:
524 case O_FUN_N:
525 case O_FUN_BC:
526 return "function";
Damien429d7192013-10-04 19:53:11 +0100527 case O_LIST:
528 return "list";
529 case O_SET:
530 return "set";
531 case O_MAP:
532 return "dict";
Damiena3977762013-10-09 23:10:10 +0100533 case O_OBJ:
534 {
535 py_map_elem_t *qn = py_qstr_map_lookup(o->u_obj.class->u_class.locals, qstr_from_str_static("__qualname__"), false);
536 assert(qn != NULL);
537 assert(IS_O(qn->value, O_STR));
538 return qstr_str(((py_obj_base_t*)qn->value)->u_str);
539 }
Damien429d7192013-10-04 19:53:11 +0100540 default:
541 assert(0);
542 return "UnknownType";
543 }
544 }
545}
546
547void py_obj_print(py_obj_t o_in) {
548 if (IS_SMALL_INT(o_in)) {
549 printf("%d", (int)FROM_SMALL_INT(o_in));
550 } else {
551 py_obj_base_t *o = o_in;
552 switch (o->kind) {
553 case O_CONST:
554 printf("%s", o->id);
555 break;
556 case O_STR:
557 // TODO need to escape chars etc
558 printf("'%s'", qstr_str(o->u_str));
559 break;
560#ifdef PY_FLOAT
561 case O_FLOAT:
Damiene4af64f2013-10-06 12:04:13 +0100562 printf("%f", o->u_flt);
Damien429d7192013-10-04 19:53:11 +0100563 break;
564#endif
565 case O_LIST:
566 printf("[");
567 for (int i = 0; i < o->u_list.len; i++) {
568 if (i > 0) {
569 printf(", ");
570 }
571 py_obj_print(o->u_list.items[i]);
572 }
573 printf("]");
574 break;
575 case O_SET:
576 {
577 bool first = true;
578 printf("{");
579 for (int i = 0; i < o->u_set.alloc; i++) {
580 if (o->u_set.table[i] != NULL) {
581 if (!first) {
582 printf(", ");
583 }
584 first = false;
585 py_obj_print(o->u_set.table[i]);
586 }
587 }
588 printf("}");
589 break;
590 }
591 case O_MAP:
592 {
593 bool first = true;
594 printf("{");
595 for (int i = 0; i < o->u_map.alloc; i++) {
596 if (o->u_map.table[i].key != NULL) {
597 if (!first) {
598 printf(", ");
599 }
600 first = false;
601 py_obj_print(o->u_map.table[i].key);
602 printf(": ");
603 py_obj_print(o->u_map.table[i].value);
604 }
605 }
606 printf("}");
607 break;
608 }
609 default:
Damiena3977762013-10-09 23:10:10 +0100610 printf("<? %d>", o->kind);
Damien429d7192013-10-04 19:53:11 +0100611 assert(0);
612 }
613 }
614}
615
616int rt_is_true(py_obj_t arg) {
617 DEBUG_OP_printf("is true %p\n", arg);
618 if (IS_SMALL_INT(arg)) {
619 if (FROM_SMALL_INT(arg) == 0) {
620 return 0;
621 } else {
622 return 1;
623 }
624 } else if (arg == py_const_none) {
625 return 0;
626 } else if (arg == py_const_false) {
627 return 0;
628 } else if (arg == py_const_true) {
629 return 1;
630 } else {
631 assert(0);
632 return 0;
633 }
634}
635
636int rt_get_int(py_obj_t arg) {
637 if (IS_SMALL_INT(arg)) {
638 return FROM_SMALL_INT(arg);
639 } else {
640 assert(0);
641 return 0;
642 }
643}
644
645py_obj_t rt_load_const_str(qstr qstr) {
646 DEBUG_OP_printf("load '%s'\n", qstr_str(qstr));
647 return py_obj_new_str(qstr);
648}
649
650py_obj_t rt_load_name(qstr qstr) {
651 // logic: search locals, globals, builtins
Damiena3977762013-10-09 23:10:10 +0100652 DEBUG_OP_printf("load name %s\n", qstr_str(qstr));
Damieneb19efb2013-10-10 22:06:54 +0100653 py_map_elem_t *elem = py_qstr_map_lookup(map_locals, qstr, false);
Damiena3977762013-10-09 23:10:10 +0100654 if (elem == NULL) {
Damieneb19efb2013-10-10 22:06:54 +0100655 elem = py_qstr_map_lookup(map_globals, qstr, false);
Damiena3977762013-10-09 23:10:10 +0100656 if (elem == NULL) {
657 elem = py_qstr_map_lookup(&map_builtins, qstr, false);
658 if (elem == NULL) {
659 printf("name doesn't exist: %s\n", qstr_str(qstr));
660 assert(0);
661 }
662 }
663 }
664 return elem->value;
665}
666
667py_obj_t rt_load_global(qstr qstr) {
668 // logic: search globals, builtins
669 DEBUG_OP_printf("load global %s\n", qstr_str(qstr));
Damieneb19efb2013-10-10 22:06:54 +0100670 py_map_elem_t *elem = py_qstr_map_lookup(map_globals, qstr, false);
Damien429d7192013-10-04 19:53:11 +0100671 if (elem == NULL) {
672 elem = py_qstr_map_lookup(&map_builtins, qstr, false);
673 if (elem == NULL) {
674 printf("name doesn't exist: %s\n", qstr_str(qstr));
675 assert(0);
676 }
677 }
678 return elem->value;
679}
680
Damien429d7192013-10-04 19:53:11 +0100681py_obj_t rt_load_build_class() {
682 DEBUG_OP_printf("load_build_class\n");
683 py_map_elem_t *elem = py_qstr_map_lookup(&map_builtins, q___build_class__, false);
684 if (elem == NULL) {
685 printf("name doesn't exist: __build_class__\n");
686 assert(0);
687 }
688 return elem->value;
689}
690
691void rt_store_name(qstr qstr, py_obj_t obj) {
Damiena3977762013-10-09 23:10:10 +0100692 DEBUG_OP_printf("store name %s <- %p\n", qstr_str(qstr), obj);
Damieneb19efb2013-10-10 22:06:54 +0100693 py_qstr_map_lookup(map_locals, qstr, true)->value = obj;
Damiena3977762013-10-09 23:10:10 +0100694}
695
696void rt_store_global(qstr qstr, py_obj_t obj) {
697 DEBUG_OP_printf("store global %s <- %p\n", qstr_str(qstr), obj);
Damieneb19efb2013-10-10 22:06:54 +0100698 py_qstr_map_lookup(map_globals, qstr, true)->value = obj;
Damien429d7192013-10-04 19:53:11 +0100699}
700
701py_obj_t rt_unary_op(int op, py_obj_t arg) {
702 assert(0);
703 return py_const_none;
704}
705
706py_obj_t rt_binary_op(int op, py_obj_t lhs, py_obj_t rhs) {
707 DEBUG_OP_printf("binary %d %p %p\n", op, lhs, rhs);
708 if (op == RT_BINARY_OP_SUBSCR) {
709 if (IS_O(lhs, O_LIST) && IS_SMALL_INT(rhs)) {
710 return ((py_obj_base_t*)lhs)->u_list.items[FROM_SMALL_INT(rhs)];
711 } else {
712 assert(0);
713 }
714 } else if (IS_SMALL_INT(lhs) && IS_SMALL_INT(rhs)) {
715 py_small_int_t val;
716 switch (op) {
717 case RT_BINARY_OP_ADD:
718 case RT_BINARY_OP_INPLACE_ADD: val = FROM_SMALL_INT(lhs) + FROM_SMALL_INT(rhs); break;
719 case RT_BINARY_OP_SUBTRACT: val = FROM_SMALL_INT(lhs) - FROM_SMALL_INT(rhs); break;
720 case RT_BINARY_OP_MULTIPLY: val = FROM_SMALL_INT(lhs) * FROM_SMALL_INT(rhs); break;
721 case RT_BINARY_OP_FLOOR_DIVIDE: val = FROM_SMALL_INT(lhs) / FROM_SMALL_INT(rhs); break;
722#ifdef PY_FLOAT
723 case RT_BINARY_OP_TRUE_DIVIDE: return py_obj_new_float((float_t)FROM_SMALL_INT(lhs) / (float_t)FROM_SMALL_INT(rhs));
724#endif
725 default: printf("%d\n", op); assert(0); val = 0;
726 }
727 if (fit_small_int(val)) {
728 return TO_SMALL_INT(val);
729 }
730 } else if (IS_O(lhs, O_STR) && IS_O(rhs, O_STR)) {
731 const char *lhs_str = qstr_str(((py_obj_base_t*)lhs)->u_str);
732 const char *rhs_str = qstr_str(((py_obj_base_t*)rhs)->u_str);
733 char *val;
734 switch (op) {
735 case RT_BINARY_OP_ADD:
736 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;
737 default: printf("%d\n", op); assert(0); val = NULL;
738 }
739 return py_obj_new_str(qstr_from_str_take(val));
740 }
741 assert(0);
742 return py_const_none;
743}
744
745py_obj_t rt_compare_op(int op, py_obj_t lhs, py_obj_t rhs) {
746 DEBUG_OP_printf("compare %d %p %p\n", op, lhs, rhs);
747 if (IS_SMALL_INT(lhs) && IS_SMALL_INT(rhs)) {
748 int cmp;
749 switch (op) {
750 case RT_COMPARE_OP_LESS: cmp = FROM_SMALL_INT(lhs) < FROM_SMALL_INT(rhs); break;
751 case RT_COMPARE_OP_MORE: cmp = FROM_SMALL_INT(lhs) > FROM_SMALL_INT(rhs); break;
752 default: assert(0); cmp = 0;
753 }
754 if (cmp) {
755 return py_const_true;
756 } else {
757 return py_const_false;
758 }
759 }
760 assert(0);
761 return py_const_none;
762}
763
764py_obj_t rt_make_function_from_id(int unique_code_id) {
Damienb05d7072013-10-05 13:37:10 +0100765 DEBUG_OP_printf("make_function_from_id %d\n", unique_code_id);
766 if (unique_code_id < 1 || unique_code_id >= next_unique_code_id) {
Damien429d7192013-10-04 19:53:11 +0100767 // illegal code id
768 return py_const_none;
769 }
770 py_code_t *c = &unique_codes[unique_code_id];
771 py_obj_base_t *o = m_new(py_obj_base_t, 1);
772 switch (c->kind) {
Damien826005c2013-10-05 23:17:28 +0100773 case PY_CODE_BYTE:
774 o->kind = O_FUN_BC;
775 o->u_fun_bc.n_args = c->n_args;
776 o->u_fun_bc.code = c->u_byte.code;
777 o->u_fun_bc.len = c->u_byte.len;
778 break;
Damien429d7192013-10-04 19:53:11 +0100779 case PY_CODE_NATIVE:
780 switch (c->n_args) {
781 case 0: o->kind = O_FUN_0; break;
782 case 1: o->kind = O_FUN_1; break;
783 case 2: o->kind = O_FUN_2; break;
784 default: assert(0);
785 }
786 o->u_fun.fun = c->u_native.fun;
787 break;
Damien826005c2013-10-05 23:17:28 +0100788 case PY_CODE_INLINE_ASM:
789 o->kind = O_FUN_ASM;
790 o->u_fun_asm.n_args = c->n_args;
791 o->u_fun_asm.fun = c->u_inline_asm.fun;
Damien429d7192013-10-04 19:53:11 +0100792 break;
793 default:
794 assert(0);
795 }
796 return o;
797}
798
799py_obj_t rt_make_function_0(py_fun_0_t fun) {
800 py_obj_base_t *o = m_new(py_obj_base_t, 1);
801 o->kind = O_FUN_0;
802 o->u_fun.fun = fun;
803 return o;
804}
805
806py_obj_t rt_make_function_1(py_fun_1_t fun) {
807 py_obj_base_t *o = m_new(py_obj_base_t, 1);
808 o->kind = O_FUN_1;
809 o->u_fun.fun = fun;
810 return o;
811}
812
813py_obj_t rt_make_function_2(py_fun_2_t fun) {
814 py_obj_base_t *o = m_new(py_obj_base_t, 1);
815 o->kind = O_FUN_2;
816 o->u_fun.fun = fun;
817 return o;
818}
819
820py_obj_t rt_make_function(int n_args, py_fun_t code) {
821 // assumes code is a pointer to a py_fun_t (i think this is safe...)
822 py_obj_base_t *o = m_new(py_obj_base_t, 1);
823 o->kind = O_FUN_N;
Damien429d7192013-10-04 19:53:11 +0100824 o->u_fun.n_args = n_args;
Damien826005c2013-10-05 23:17:28 +0100825 o->u_fun.fun = code;
Damien429d7192013-10-04 19:53:11 +0100826 return o;
827}
828
Damieneb19efb2013-10-10 22:06:54 +0100829py_obj_t rt_call_function_0(py_obj_t fun) {
830 return rt_call_function_n(fun, 0, NULL);
831}
832
833py_obj_t rt_call_function_1(py_obj_t fun, py_obj_t arg) {
834 return rt_call_function_n(fun, 1, &arg);
835}
836
837py_obj_t rt_call_function_2(py_obj_t fun, py_obj_t arg1, py_obj_t arg2) {
838 py_obj_t args[2];
839 args[1] = arg1;
840 args[0] = arg2;
841 return rt_call_function_n(fun, 2, args);
842}
843
844typedef machine_uint_t (*inline_asm_fun_0_t)();
845typedef machine_uint_t (*inline_asm_fun_1_t)(machine_uint_t);
846typedef machine_uint_t (*inline_asm_fun_2_t)(machine_uint_t, machine_uint_t);
847typedef machine_uint_t (*inline_asm_fun_3_t)(machine_uint_t, machine_uint_t, machine_uint_t);
848
Damiene4af64f2013-10-06 12:04:13 +0100849// convert a Python object to a sensible value for inline asm
850machine_uint_t rt_convert_obj_for_inline_asm(py_obj_t obj) {
851 // TODO for byte_array, pass pointer to the array
852 if (IS_SMALL_INT(obj)) {
853 return FROM_SMALL_INT(obj);
854 } else if (obj == py_const_none) {
855 return 0;
856 } else if (obj == py_const_false) {
857 return 0;
858 } else if (obj == py_const_true) {
859 return 1;
860 } else {
861 py_obj_base_t *o = obj;
862 switch (o->kind) {
863 case O_STR:
864 // pointer to the string (it's probably constant though!)
865 return (machine_uint_t)qstr_str(o->u_str);
866
867 case O_FLOAT:
868 // convert float to int (could also pass in float registers)
869 return (machine_int_t)o->u_flt;
870
871 case O_LIST:
872 // pointer to start of list (could pass length, but then could use len(x) for that)
873 return (machine_uint_t)o->u_list.items;
874
875 default:
876 // just pass along a pointer to the object
877 return (machine_uint_t)obj;
878 }
879 }
880}
881
882// convert a return value from inline asm to a sensible Python object
883py_obj_t rt_convert_val_from_inline_asm(machine_uint_t val) {
884 return TO_SMALL_INT(val);
885}
886
Damieneb19efb2013-10-10 22:06:54 +0100887// args are in reverse order in the array
888py_obj_t rt_call_function_n(py_obj_t fun, int n_args, const py_obj_t *args) {
889 int n_args_fun = 0;
Damien429d7192013-10-04 19:53:11 +0100890 if (IS_O(fun, O_FUN_0)) {
891 py_obj_base_t *o = fun;
Damieneb19efb2013-10-10 22:06:54 +0100892 if (n_args != 0) {
893 n_args_fun = 0;
894 goto bad_n_args;
895 }
896 DEBUG_OP_printf("calling native %p()\n", o->u_fun.fun);
Damien429d7192013-10-04 19:53:11 +0100897 return ((py_fun_0_t)o->u_fun.fun)();
Damieneb19efb2013-10-10 22:06:54 +0100898
899 } else if (IS_O(fun, O_FUN_1)) {
900 py_obj_base_t *o = fun;
901 if (n_args != 1) {
902 n_args_fun = 1;
903 goto bad_n_args;
904 }
905 DEBUG_OP_printf("calling native %p(%p)\n", o->u_fun.fun, args[0]);
906 return ((py_fun_1_t)o->u_fun.fun)(args[0]);
907
908 } else if (IS_O(fun, O_FUN_2)) {
909 py_obj_base_t *o = fun;
910 if (n_args != 2) {
911 n_args_fun = 2;
912 goto bad_n_args;
913 }
914 DEBUG_OP_printf("calling native %p(%p, %p)\n", o->u_fun.fun, args[1], args[0]);
915 return ((py_fun_2_t)o->u_fun.fun)(args[1], args[0]);
916
917 // TODO O_FUN_N
918
Damien429d7192013-10-04 19:53:11 +0100919 } else if (IS_O(fun, O_FUN_BC)) {
920 py_obj_base_t *o = fun;
Damieneb19efb2013-10-10 22:06:54 +0100921 if (n_args != o->u_fun_bc.n_args) {
922 n_args_fun = o->u_fun_bc.n_args;
923 goto bad_n_args;
924 }
925 DEBUG_OP_printf("calling byte code %p(n_args=%d)\n", o->u_fun_bc.code, n_args);
926 return py_execute_byte_code(o->u_fun_bc.code, o->u_fun_bc.len, args, n_args);
927
Damiene4af64f2013-10-06 12:04:13 +0100928 } else if (IS_O(fun, O_FUN_ASM)) {
929 py_obj_base_t *o = fun;
Damieneb19efb2013-10-10 22:06:54 +0100930 if (n_args != o->u_fun_asm.n_args) {
931 n_args_fun = o->u_fun_asm.n_args;
932 goto bad_n_args;
933 }
934 DEBUG_OP_printf("calling inline asm %p(n_args=%d)\n", o->u_fun_asm.fun, n_args);
935 machine_uint_t ret;
936 if (n_args == 0) {
937 ret = ((inline_asm_fun_0_t)o->u_fun_asm.fun)();
938 } else if (n_args == 1) {
939 ret = ((inline_asm_fun_1_t)o->u_fun_asm.fun)(rt_convert_obj_for_inline_asm(args[0]));
940 } else if (n_args == 2) {
941 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]));
942 } else if (n_args == 3) {
943 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]));
944 } else {
945 assert(0);
946 ret = 0;
947 }
948 return rt_convert_val_from_inline_asm(ret);
949
Damiena3977762013-10-09 23:10:10 +0100950 } else if (IS_O(fun, O_BOUND_METH)) {
951 py_obj_base_t *o = fun;
Damieneb19efb2013-10-10 22:06:54 +0100952 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);
953 if (n_args == 0) {
954 return rt_call_function_n(o->u_bound_meth.meth, 1, &o->u_bound_meth.self);
955 } else if (n_args == 1) {
956 py_obj_t args2[2];
957 args2[1] = o->u_bound_meth.self;
958 args2[0] = args[0];
959 return rt_call_function_n(o->u_bound_meth.meth, 2, args2);
960 } else {
961 // TODO not implemented
962 assert(0);
963 return py_const_none;
964 //return rt_call_function_2(o->u_bound_meth.meth, n_args + 1, o->u_bound_meth.self + args);
965 }
966
Damiena3977762013-10-09 23:10:10 +0100967 } else if (IS_O(fun, O_CLASS)) {
968 // instantiate an instance of a class
Damieneb19efb2013-10-10 22:06:54 +0100969 if (n_args != 0) {
970 n_args_fun = 0;
971 goto bad_n_args;
972 }
Damiena3977762013-10-09 23:10:10 +0100973 DEBUG_OP_printf("instantiate object of class %p with no args\n", fun);
974 py_obj_base_t *o = m_new(py_obj_base_t, 1);
975 o->kind = O_OBJ;
976 o->u_obj.class = fun;
977 o->u_obj.members = py_map_new(MAP_QSTR, 0);
978 return o;
Damieneb19efb2013-10-10 22:06:54 +0100979
Damien429d7192013-10-04 19:53:11 +0100980 } else {
Damieneb19efb2013-10-10 22:06:54 +0100981 printf("fun %p %d\n", fun, ((py_obj_base_t*)fun)->kind);
Damien429d7192013-10-04 19:53:11 +0100982 assert(0);
983 return py_const_none;
984 }
Damien429d7192013-10-04 19:53:11 +0100985
Damieneb19efb2013-10-10 22:06:54 +0100986bad_n_args:
987 printf("TypeError: function takes %d positional arguments but %d were given\n", n_args_fun, n_args);
988 assert(0);
989 return py_const_none;
Damien429d7192013-10-04 19:53:11 +0100990}
991
Damiena3977762013-10-09 23:10:10 +0100992// args contains: arg(n_args-1) arg(n_args-2) ... arg(0) self/NULL fun
993// if n_args==0 then there are only self/NULL and fun
994py_obj_t rt_call_method_n(int n_args, const py_obj_t *args) {
Damien7f5dacf2013-10-10 11:24:39 +0100995 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 +0100996 return rt_call_function_n(args[n_args + 1], n_args + ((args[n_args] == NULL) ? 0 : 1), args);
997}
998
Damien429d7192013-10-04 19:53:11 +0100999// items are in reverse order
1000py_obj_t rt_build_list(int n_args, py_obj_t *items) {
1001 py_obj_base_t *o = m_new(py_obj_base_t, 1);
1002 o->kind = O_LIST;
1003 o->u_list.alloc = n_args;
1004 if (o->u_list.alloc < 4) {
1005 o->u_list.alloc = 4;
1006 }
1007 o->u_list.len = n_args;
1008 o->u_list.items = m_new(py_obj_t, o->u_list.alloc);
1009 for (int i = 0; i < n_args; i++) {
1010 o->u_list.items[i] = items[n_args - i - 1];
1011 }
1012 return o;
1013}
1014
1015py_obj_t py_set_lookup(py_obj_t o_in, py_obj_t index, bool add_if_not_found) {
1016 assert(IS_O(o_in, O_SET));
1017 py_obj_base_t *o = o_in;
1018 int hash = py_obj_hash(index);
1019 int pos = hash % o->u_set.alloc;
1020 for (;;) {
1021 py_obj_t elem = o->u_set.table[pos];
1022 if (elem == NULL) {
1023 // not in table
1024 if (add_if_not_found) {
1025 if (o->u_set.used + 1 >= o->u_set.alloc) {
1026 // not enough room in table, rehash it
1027 int old_alloc = o->u_set.alloc;
1028 py_obj_t *old_table = o->u_set.table;
1029 o->u_set.alloc = get_doubling_prime_greater_or_equal_to(o->u_set.alloc + 1);
1030 o->u_set.used = 0;
1031 o->u_set.table = m_new(py_obj_t, o->u_set.alloc);
1032 for (int i = 0; i < old_alloc; i++) {
1033 if (old_table[i] != NULL) {
1034 py_set_lookup(o, old_table[i], true);
1035 }
1036 }
1037 m_free(old_table);
1038 // restart the search for the new element
1039 pos = hash % o->u_set.alloc;
1040 } else {
1041 o->u_set.used += 1;
1042 o->u_set.table[pos] = index;
1043 return index;
1044 }
1045 } else {
1046 return NULL;
1047 }
1048 } else if (py_obj_equal(elem, index)) {
1049 // found it
1050 return elem;
1051 } else {
1052 // not yet found, keep searching in this table
1053 pos = (pos + 1) % o->u_set.alloc;
1054 }
1055 }
1056}
1057
1058py_obj_t rt_build_set(int n_args, py_obj_t *items) {
1059 py_obj_base_t *o = m_new(py_obj_base_t, 1);
1060 o->kind = O_SET;
1061 o->u_set.alloc = get_doubling_prime_greater_or_equal_to(n_args + 1);
1062 o->u_set.used = 0;
1063 o->u_set.table = m_new(py_obj_t, o->u_set.alloc);
1064 for (int i = 0; i < o->u_set.alloc; i++) {
1065 o->u_set.table[i] = NULL;
1066 }
1067 for (int i = 0; i < n_args; i++) {
1068 py_set_lookup(o, items[i], true);
1069 }
1070 return o;
1071}
1072
1073py_obj_t rt_build_map(int n_args) {
1074 py_obj_base_t *o = m_new(py_obj_base_t, 1);
1075 o->kind = O_MAP;
1076 py_map_init(&o->u_map, MAP_PY_OBJ, n_args);
1077 return o;
1078}
1079
1080py_obj_t rt_store_map(py_obj_t map, py_obj_t key, py_obj_t value) {
1081 assert(IS_O(map, O_MAP)); // should always be
1082 py_map_lookup(map, key, true)->value = value;
1083 return map;
1084}
1085
Damiena3977762013-10-09 23:10:10 +01001086py_obj_t build_bound_method(py_obj_t self, py_obj_t meth) {
1087 py_obj_base_t *o = m_new(py_obj_base_t, 1);
1088 o->kind = O_BOUND_METH;
1089 o->u_bound_meth.meth = meth;
1090 o->u_bound_meth.self = self;
1091 return o;
1092}
1093
1094py_obj_t rt_load_attr(py_obj_t base, qstr attr) {
1095 DEBUG_OP_printf("load attr %s\n", qstr_str(attr));
1096 if (IS_O(base, O_LIST) && attr == q_append) {
1097 return build_bound_method(base, fun_list_append);
1098 } else if (IS_O(base, O_CLASS)) {
1099 py_obj_base_t *o = base;
1100 py_map_elem_t *elem = py_qstr_map_lookup(o->u_class.locals, attr, false);
1101 if (elem == NULL) {
1102 goto no_attr;
1103 }
1104 return elem->value;
1105 } else if (IS_O(base, O_OBJ)) {
1106 // logic: look in obj members then class locals (TODO check this against CPython)
1107 py_obj_base_t *o = base;
1108 py_map_elem_t *elem = py_qstr_map_lookup(o->u_obj.members, attr, false);
1109 if (elem != NULL) {
1110 // object member, always treated as a value
1111 return elem->value;
1112 }
1113 elem = py_qstr_map_lookup(o->u_obj.class->u_class.locals, attr, false);
1114 if (elem != NULL) {
1115 if (py_obj_is_callable(elem->value)) {
1116 // class member is callable so build a bound method
1117 return build_bound_method(base, elem->value);
1118 } else {
1119 // class member is a value, so just return that value
1120 return elem->value;
1121 }
1122 }
1123 goto no_attr;
1124 }
1125
1126no_attr:
1127 printf("AttributeError: '%s' object has no attribute '%s'\n", py_obj_get_type_str(base), qstr_str(attr));
1128 assert(0);
1129 return py_const_none;
1130}
1131
1132void rt_load_method(py_obj_t base, qstr attr, py_obj_t *dest) {
1133 DEBUG_OP_printf("load method %s\n", qstr_str(attr));
1134 if (IS_O(base, O_LIST) && attr == q_append) {
1135 dest[1] = fun_list_append;
1136 dest[0] = base;
1137 return;
1138 } else if (IS_O(base, O_OBJ)) {
1139 // logic: look in obj members then class locals (TODO check this against CPython)
1140 py_obj_base_t *o = base;
1141 py_map_elem_t *elem = py_qstr_map_lookup(o->u_obj.members, attr, false);
1142 if (elem != NULL) {
1143 // object member, always treated as a value
1144 dest[1] = elem->value;
1145 dest[0] = NULL;
1146 return;
1147 }
1148 elem = py_qstr_map_lookup(o->u_obj.class->u_class.locals, attr, false);
1149 if (elem != NULL) {
1150 if (py_obj_is_callable(elem->value)) {
1151 // class member is callable so build a bound method
1152 dest[1] = elem->value;
1153 dest[0] = base;
1154 return;
1155 } else {
1156 // class member is a value, so just return that value
1157 dest[1] = elem->value;
1158 dest[0] = NULL;
1159 return;
1160 }
1161 }
1162 goto no_attr;
1163 }
1164
1165no_attr:
1166 dest[1] = rt_load_attr(base, attr);
1167 dest[0] = NULL;
1168}
1169
1170void rt_store_attr(py_obj_t base, qstr attr, py_obj_t val) {
1171 DEBUG_OP_printf("store attr %p.%s <- %p\n", base, qstr_str(attr), val);
1172 if (IS_O(base, O_OBJ)) {
1173 // logic: look in class locals (no add) then obj members (add) (TODO check this against CPython)
1174 py_obj_base_t *o = base;
1175 py_map_elem_t *elem = py_qstr_map_lookup(o->u_obj.class->u_class.locals, attr, false);
1176 if (elem != NULL) {
1177 elem->value = val;
1178 } else {
1179 elem = py_qstr_map_lookup(o->u_obj.class->u_class.locals, attr, true)->value = val;
1180 }
1181 } else {
1182 printf("?AttributeError: '%s' object has no attribute '%s'\n", py_obj_get_type_str(base), qstr_str(attr));
1183 assert(0);
1184 }
1185}
1186
Damien429d7192013-10-04 19:53:11 +01001187void rt_store_subscr(py_obj_t base, py_obj_t index, py_obj_t value) {
1188 if (IS_O(base, O_LIST) && IS_SMALL_INT(index)) {
1189 // list store
1190 py_obj_base_t *o = base;
1191 int idx = FROM_SMALL_INT(index);
1192 if (idx < 0) {
1193 idx += o->u_list.len;
1194 }
1195 if (0 <= idx && idx < o->u_list.len) {
1196 o->u_list.items[idx] = value;
1197 } else {
1198 assert(0);
1199 }
1200 } else if (IS_O(base, O_MAP)) {
1201 // map store
1202 py_map_lookup(base, index, true)->value = value;
1203 } else {
1204 assert(0);
1205 }
1206}
1207
Damien429d7192013-10-04 19:53:11 +01001208void *rt_fun_table[RT_F_NUMBER_OF] = {
1209 rt_load_const_str,
1210 rt_load_name,
1211 rt_load_global,
Damien7f5dacf2013-10-10 11:24:39 +01001212 rt_load_build_class,
Damien429d7192013-10-04 19:53:11 +01001213 rt_load_attr,
1214 rt_load_method,
1215 rt_store_name,
Damien7f5dacf2013-10-10 11:24:39 +01001216 rt_store_attr,
Damien429d7192013-10-04 19:53:11 +01001217 rt_store_subscr,
1218 rt_is_true,
1219 rt_unary_op,
1220 rt_build_list,
1221 rt_build_map,
1222 rt_store_map,
1223 rt_build_set,
1224 rt_make_function_from_id,
Damieneb19efb2013-10-10 22:06:54 +01001225 rt_call_function_n,
Damien7f5dacf2013-10-10 11:24:39 +01001226 rt_call_method_n,
Damien429d7192013-10-04 19:53:11 +01001227 rt_binary_op,
1228 rt_compare_op,
1229};
1230
1231/*
1232void rt_f_vector(rt_fun_kind_t fun_kind) {
1233 (rt_f_table[fun_kind])();
1234}
1235*/