Damien
11 years ago
10 changed files with 1057 additions and 943 deletions
@ -0,0 +1,113 @@ |
|||
#include <stdint.h> |
|||
#include <stdlib.h> |
|||
#include <stdio.h> |
|||
#include <stdarg.h> |
|||
#include <string.h> |
|||
#include <assert.h> |
|||
|
|||
#include "nlr.h" |
|||
#include "misc.h" |
|||
#include "mpyconfig.h" |
|||
#include "runtime.h" |
|||
#include "bc.h" |
|||
|
|||
#include "map.h" |
|||
#include "obj.h" |
|||
#include "objprivate.h" |
|||
#include "builtin.h" |
|||
|
|||
py_obj_t py_builtin___repl_print__(py_obj_t o) { |
|||
if (o != py_const_none) { |
|||
py_obj_print(o); |
|||
printf("\n"); |
|||
} |
|||
return py_const_none; |
|||
} |
|||
|
|||
py_obj_t py_builtin_print(int n_args, const py_obj_t* args) { |
|||
for (int i = 0; i < n_args; i++) { |
|||
if (i > 0) { |
|||
printf(" "); |
|||
} |
|||
if (IS_O(args[i], O_STR)) { |
|||
// special case, print string raw
|
|||
printf("%s", qstr_str(((py_obj_base_t*)args[i])->u_str)); |
|||
} else { |
|||
// print the object Python style
|
|||
py_obj_print(args[i]); |
|||
} |
|||
} |
|||
printf("\n"); |
|||
return py_const_none; |
|||
} |
|||
|
|||
py_obj_t py_builtin_len(py_obj_t o_in) { |
|||
py_small_int_t len = 0; |
|||
if (IS_O(o_in, O_STR)) { |
|||
py_obj_base_t *o = o_in; |
|||
len = strlen(qstr_str(o->u_str)); |
|||
} else if (IS_O(o_in, O_TUPLE) || IS_O(o_in, O_LIST)) { |
|||
py_obj_base_t *o = o_in; |
|||
len = o->u_tuple_list.len; |
|||
} else if (IS_O(o_in, O_MAP)) { |
|||
py_obj_base_t *o = o_in; |
|||
len = o->u_map.used; |
|||
} else { |
|||
assert(0); |
|||
} |
|||
return TO_SMALL_INT(len); |
|||
} |
|||
|
|||
py_obj_t py_builtin_abs(py_obj_t o_in) { |
|||
if (IS_SMALL_INT(o_in)) { |
|||
py_small_int_t val = FROM_SMALL_INT(o_in); |
|||
if (val < 0) { |
|||
val = -val; |
|||
} |
|||
return TO_SMALL_INT(val); |
|||
#if MICROPY_ENABLE_FLOAT |
|||
} else if (IS_O(o_in, O_FLOAT)) { |
|||
py_obj_base_t *o = o_in; |
|||
// TODO check for NaN etc
|
|||
if (o->u_float < 0) { |
|||
return py_obj_new_float(-o->u_float); |
|||
} else { |
|||
return o_in; |
|||
} |
|||
} else if (IS_O(o_in, O_COMPLEX)) { |
|||
py_obj_base_t *o = o_in; |
|||
return py_obj_new_float(machine_sqrt(o->u_complex.real*o->u_complex.real + o->u_complex.imag*o->u_complex.imag)); |
|||
#endif |
|||
} else { |
|||
assert(0); |
|||
return py_const_none; |
|||
} |
|||
} |
|||
|
|||
py_obj_t py_builtin___build_class__(py_obj_t o_class_fun, py_obj_t o_class_name) { |
|||
// we differ from CPython: we set the new __locals__ object here
|
|||
py_map_t *old_locals = rt_get_map_locals(); |
|||
py_map_t *class_locals = py_map_new(MAP_QSTR, 0); |
|||
rt_set_map_locals(class_locals); |
|||
|
|||
// call the class code
|
|||
rt_call_function_1(o_class_fun, (py_obj_t)0xdeadbeef); |
|||
|
|||
// restore old __locals__ object
|
|||
rt_set_map_locals(old_locals); |
|||
|
|||
// create and return the new class
|
|||
py_obj_base_t *o = m_new(py_obj_base_t, 1); |
|||
o->kind = O_CLASS; |
|||
o->u_class.locals = class_locals; |
|||
return o; |
|||
} |
|||
|
|||
py_obj_t py_builtin_range(int n_args, const py_obj_t* args) { |
|||
switch (n_args) { |
|||
case 1: return py_obj_new_range(0, py_obj_get_int(args[0]), 1); |
|||
case 2: return py_obj_new_range(py_obj_get_int(args[0]), py_obj_get_int(args[1]), 1); |
|||
case 3: return py_obj_new_range(py_obj_get_int(args[0]), py_obj_get_int(args[1]), py_obj_get_int(args[2])); |
|||
default: nlr_jump(py_obj_new_exception_2(rt_q_TypeError, "range expected at most 3 arguments, got %d", (void*)(machine_int_t)n_args, NULL)); |
|||
} |
|||
} |
@ -0,0 +1,6 @@ |
|||
py_obj_t py_builtin___repl_print__(py_obj_t o); |
|||
py_obj_t py_builtin_print(int n_args, const py_obj_t* args); |
|||
py_obj_t py_builtin_len(py_obj_t o_in); |
|||
py_obj_t py_builtin_abs(py_obj_t o_in); |
|||
py_obj_t py_builtin___build_class__(py_obj_t o_class_fun, py_obj_t o_class_name); |
|||
py_obj_t py_builtin_range(int n_args, const py_obj_t* args); |
@ -0,0 +1,143 @@ |
|||
#include <stdint.h> |
|||
#include <stdlib.h> |
|||
#include <assert.h> |
|||
|
|||
#include "misc.h" |
|||
#include "mpyconfig.h" |
|||
#include "runtime.h" |
|||
|
|||
#include "map.h" |
|||
#include "obj.h" |
|||
#include "objprivate.h" |
|||
|
|||
// approximatelly doubling primes; made with Mathematica command: Table[Prime[Floor[(1.7)^n]], {n, 3, 24}]
|
|||
static 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}; |
|||
|
|||
int get_doubling_prime_greater_or_equal_to(int x) { |
|||
for (int i = 0; i < sizeof(doubling_primes) / sizeof(int); i++) { |
|||
if (doubling_primes[i] >= x) { |
|||
return doubling_primes[i]; |
|||
} |
|||
} |
|||
// ran out of primes in the table!
|
|||
// return something sensible, at least make it odd
|
|||
return x | 1; |
|||
} |
|||
|
|||
void py_map_init(py_map_t *map, py_map_kind_t kind, int n) { |
|||
map->kind = kind; |
|||
map->used = 0; |
|||
map->alloc = get_doubling_prime_greater_or_equal_to(n + 1); |
|||
map->table = m_new0(py_map_elem_t, map->alloc); |
|||
} |
|||
|
|||
py_map_t *py_map_new(py_map_kind_t kind, int n) { |
|||
py_map_t *map = m_new(py_map_t, 1); |
|||
py_map_init(map, kind, n); |
|||
return map; |
|||
} |
|||
|
|||
py_map_elem_t* py_map_lookup_helper(py_map_t *map, py_obj_t index, bool add_if_not_found) { |
|||
bool is_map_py_obj = (map->kind == MAP_PY_OBJ); |
|||
machine_uint_t hash; |
|||
if (is_map_py_obj) { |
|||
hash = py_obj_hash(index); |
|||
} else { |
|||
hash = (machine_uint_t)index; |
|||
} |
|||
uint pos = hash % map->alloc; |
|||
for (;;) { |
|||
py_map_elem_t *elem = &map->table[pos]; |
|||
if (elem->key == NULL) { |
|||
// not in table
|
|||
if (add_if_not_found) { |
|||
if (map->used + 1 >= map->alloc) { |
|||
// not enough room in table, rehash it
|
|||
int old_alloc = map->alloc; |
|||
py_map_elem_t *old_table = map->table; |
|||
map->alloc = get_doubling_prime_greater_or_equal_to(map->alloc + 1); |
|||
map->used = 0; |
|||
map->table = m_new0(py_map_elem_t, map->alloc); |
|||
for (int i = 0; i < old_alloc; i++) { |
|||
if (old_table[i].key != NULL) { |
|||
py_map_lookup_helper(map, old_table[i].key, true)->value = old_table[i].value; |
|||
} |
|||
} |
|||
m_free(old_table); |
|||
// restart the search for the new element
|
|||
pos = hash % map->alloc; |
|||
} else { |
|||
map->used += 1; |
|||
elem->key = index; |
|||
return elem; |
|||
} |
|||
} else { |
|||
return NULL; |
|||
} |
|||
} else if (elem->key == index || (is_map_py_obj && py_obj_equal(elem->key, index))) { |
|||
// found it
|
|||
/* it seems CPython does not replace the index; try x={True:'true'};x[1]='one';x
|
|||
if (add_if_not_found) { |
|||
elem->key = index; |
|||
} |
|||
*/ |
|||
return elem; |
|||
} else { |
|||
// not yet found, keep searching in this table
|
|||
pos = (pos + 1) % map->alloc; |
|||
} |
|||
} |
|||
} |
|||
|
|||
py_map_elem_t* py_qstr_map_lookup(py_map_t *map, qstr index, bool add_if_not_found) { |
|||
py_obj_t o = (py_obj_t)(machine_uint_t)index; |
|||
return py_map_lookup_helper(map, o, add_if_not_found); |
|||
} |
|||
|
|||
py_map_elem_t* py_map_lookup(py_obj_t o, py_obj_t index, bool add_if_not_found) { |
|||
assert(IS_O(o, O_MAP)); |
|||
return py_map_lookup_helper(&((py_obj_base_t *)o)->u_map, index, add_if_not_found); |
|||
} |
|||
|
|||
py_obj_t py_set_lookup(py_obj_t o_in, py_obj_t index, bool add_if_not_found) { |
|||
assert(IS_O(o_in, O_SET)); |
|||
py_obj_base_t *o = o_in; |
|||
int hash = py_obj_hash(index); |
|||
int pos = hash % o->u_set.alloc; |
|||
for (;;) { |
|||
py_obj_t elem = o->u_set.table[pos]; |
|||
if (elem == NULL) { |
|||
// not in table
|
|||
if (add_if_not_found) { |
|||
if (o->u_set.used + 1 >= o->u_set.alloc) { |
|||
// not enough room in table, rehash it
|
|||
int old_alloc = o->u_set.alloc; |
|||
py_obj_t *old_table = o->u_set.table; |
|||
o->u_set.alloc = get_doubling_prime_greater_or_equal_to(o->u_set.alloc + 1); |
|||
o->u_set.used = 0; |
|||
o->u_set.table = m_new(py_obj_t, o->u_set.alloc); |
|||
for (int i = 0; i < old_alloc; i++) { |
|||
if (old_table[i] != NULL) { |
|||
py_set_lookup(o, old_table[i], true); |
|||
} |
|||
} |
|||
m_free(old_table); |
|||
// restart the search for the new element
|
|||
pos = hash % o->u_set.alloc; |
|||
} else { |
|||
o->u_set.used += 1; |
|||
o->u_set.table[pos] = index; |
|||
return index; |
|||
} |
|||
} else { |
|||
return NULL; |
|||
} |
|||
} else if (py_obj_equal(elem, index)) { |
|||
// found it
|
|||
return elem; |
|||
} else { |
|||
// not yet found, keep searching in this table
|
|||
pos = (pos + 1) % o->u_set.alloc; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,30 @@ |
|||
typedef enum { |
|||
MAP_QSTR, |
|||
MAP_PY_OBJ, |
|||
} py_map_kind_t; |
|||
|
|||
typedef struct _py_map_elem_t { |
|||
py_obj_t key; |
|||
py_obj_t value; |
|||
} py_map_elem_t; |
|||
|
|||
typedef struct _py_map_t { |
|||
struct { |
|||
py_map_kind_t kind : 1; |
|||
machine_uint_t used : (8 * BYTES_PER_WORD - 1); |
|||
}; |
|||
machine_uint_t alloc; |
|||
py_map_elem_t *table; |
|||
} py_map_t; |
|||
|
|||
// these are defined in runtime.c
|
|||
py_map_t *rt_get_map_locals(void); |
|||
void rt_set_map_locals(py_map_t *m); |
|||
|
|||
int get_doubling_prime_greater_or_equal_to(int x); |
|||
void py_map_init(py_map_t *map, py_map_kind_t kind, int n); |
|||
py_map_t *py_map_new(py_map_kind_t kind, int n); |
|||
py_map_elem_t* py_map_lookup_helper(py_map_t *map, py_obj_t index, bool add_if_not_found); |
|||
py_map_elem_t* py_qstr_map_lookup(py_map_t *map, qstr index, bool add_if_not_found); |
|||
py_map_elem_t* py_map_lookup(py_obj_t o, py_obj_t index, bool add_if_not_found); |
|||
py_obj_t py_set_lookup(py_obj_t o_in, py_obj_t index, bool add_if_not_found); |
@ -0,0 +1,459 @@ |
|||
#include <stdint.h> |
|||
#include <stdlib.h> |
|||
#include <stdio.h> |
|||
#include <stdarg.h> |
|||
#include <assert.h> |
|||
|
|||
#include "nlr.h" |
|||
#include "misc.h" |
|||
#include "mpyconfig.h" |
|||
#include "runtime.h" |
|||
|
|||
#include "map.h" |
|||
#include "obj.h" |
|||
#include "objprivate.h" |
|||
|
|||
py_obj_t py_obj_new_int(machine_int_t value) { |
|||
return TO_SMALL_INT(value); |
|||
} |
|||
|
|||
py_obj_t py_obj_new_const(const char *id) { |
|||
py_obj_base_t *o = m_new(py_obj_base_t, 1); |
|||
o->kind = O_CONST; |
|||
o->id = id; |
|||
return (py_obj_t)o; |
|||
} |
|||
|
|||
py_obj_t py_obj_new_str(qstr qstr) { |
|||
py_obj_base_t *o = m_new(py_obj_base_t, 1); |
|||
o->kind = O_STR; |
|||
o->u_str = qstr; |
|||
return (py_obj_t)o; |
|||
} |
|||
|
|||
#if MICROPY_ENABLE_FLOAT |
|||
py_obj_t py_obj_new_float(py_float_t val) { |
|||
py_obj_base_t *o = m_new(py_obj_base_t, 1); |
|||
o->kind = O_FLOAT; |
|||
o->u_float = val; |
|||
return (py_obj_t)o; |
|||
} |
|||
|
|||
py_obj_t py_obj_new_complex(py_float_t real, py_float_t imag) { |
|||
py_obj_base_t *o = m_new(py_obj_base_t, 1); |
|||
o->kind = O_COMPLEX; |
|||
o->u_complex.real = real; |
|||
o->u_complex.imag = imag; |
|||
return (py_obj_t)o; |
|||
} |
|||
#endif |
|||
|
|||
py_obj_t py_obj_new_exception_0(qstr id) { |
|||
py_obj_base_t *o = m_new(py_obj_base_t, 1); |
|||
o->kind = O_EXCEPTION_0; |
|||
o->u_exc0.id = id; |
|||
return (py_obj_t)o; |
|||
} |
|||
|
|||
py_obj_t py_obj_new_exception_2(qstr id, const char *fmt, const char *s1, const char *s2) { |
|||
py_obj_base_t *o = m_new(py_obj_base_t, 1); |
|||
o->kind = O_EXCEPTION_N; |
|||
o->u_exc_n.id = id; |
|||
o->u_exc_n.n_args = 3; |
|||
o->u_exc_n.args = m_new(const void*, 3); |
|||
o->u_exc_n.args[0] = fmt; |
|||
o->u_exc_n.args[1] = s1; |
|||
o->u_exc_n.args[2] = s2; |
|||
return (py_obj_t)o; |
|||
} |
|||
|
|||
// range is a class and instances are immutable sequence objects
|
|||
py_obj_t py_obj_new_range(int start, int stop, int step) { |
|||
py_obj_base_t *o = m_new(py_obj_base_t, 1); |
|||
o->kind = O_RANGE; |
|||
o->u_range.start = start; |
|||
o->u_range.stop = stop; |
|||
o->u_range.step = step; |
|||
return o; |
|||
} |
|||
|
|||
py_obj_t py_obj_new_range_iterator(int cur, int stop, int step) { |
|||
py_obj_base_t *o = m_new(py_obj_base_t, 1); |
|||
o->kind = O_RANGE_IT; |
|||
o->u_range_it.cur = cur; |
|||
o->u_range_it.stop = stop; |
|||
o->u_range_it.step = step; |
|||
return o; |
|||
} |
|||
|
|||
py_obj_t py_obj_new_tuple_iterator(py_obj_base_t *tuple, int cur) { |
|||
py_obj_base_t *o = m_new(py_obj_base_t, 1); |
|||
o->kind = O_TUPLE_IT; |
|||
o->u_tuple_list_it.obj = tuple; |
|||
o->u_tuple_list_it.cur = cur; |
|||
return o; |
|||
} |
|||
|
|||
py_obj_t py_obj_new_list_iterator(py_obj_base_t *list, int cur) { |
|||
py_obj_base_t *o = m_new(py_obj_base_t, 1); |
|||
o->kind = O_LIST_IT; |
|||
o->u_tuple_list_it.obj = list; |
|||
o->u_tuple_list_it.cur = cur; |
|||
return o; |
|||
} |
|||
|
|||
py_obj_t py_obj_new_user(const py_user_info_t *info, machine_uint_t data1, machine_uint_t data2) { |
|||
py_obj_base_t *o = m_new(py_obj_base_t, 1); |
|||
o->kind = O_USER; |
|||
// TODO should probably parse the info to turn strings to qstr's, and wrap functions in O_FUN_N objects
|
|||
// that'll take up some memory. maybe we can lazily do the O_FUN_N: leave it a ptr to a C function, and
|
|||
// only when the method is looked-up do we change that to the O_FUN_N object.
|
|||
o->u_user.info = info; |
|||
o->u_user.data1 = data1; |
|||
o->u_user.data2 = data2; |
|||
return o; |
|||
} |
|||
|
|||
const char *py_obj_get_type_str(py_obj_t o_in) { |
|||
if (IS_SMALL_INT(o_in)) { |
|||
return "int"; |
|||
} else { |
|||
py_obj_base_t *o = o_in; |
|||
switch (o->kind) { |
|||
case O_CONST: |
|||
if (o == py_const_none) { |
|||
return "NoneType"; |
|||
} else { |
|||
return "bool"; |
|||
} |
|||
case O_STR: |
|||
return "str"; |
|||
#if MICROPY_ENABLE_FLOAT |
|||
case O_FLOAT: |
|||
return "float"; |
|||
#endif |
|||
case O_FUN_0: |
|||
case O_FUN_1: |
|||
case O_FUN_2: |
|||
case O_FUN_N: |
|||
case O_FUN_VAR: |
|||
case O_FUN_BC: |
|||
return "function"; |
|||
case O_GEN_INSTANCE: |
|||
return "generator"; |
|||
case O_TUPLE: |
|||
return "tuple"; |
|||
case O_LIST: |
|||
return "list"; |
|||
case O_TUPLE_IT: |
|||
return "tuple_iterator"; |
|||
case O_LIST_IT: |
|||
return "list_iterator"; |
|||
case O_SET: |
|||
return "set"; |
|||
case O_MAP: |
|||
return "dict"; |
|||
case O_OBJ: |
|||
{ |
|||
py_map_elem_t *qn = py_qstr_map_lookup(o->u_obj.class->u_class.locals, qstr_from_str_static("__qualname__"), false); |
|||
assert(qn != NULL); |
|||
assert(IS_O(qn->value, O_STR)); |
|||
return qstr_str(((py_obj_base_t*)qn->value)->u_str); |
|||
} |
|||
case O_USER: |
|||
return o->u_user.info->type_name; |
|||
default: |
|||
assert(0); |
|||
return "UnknownType"; |
|||
} |
|||
} |
|||
} |
|||
|
|||
void printf_wrapper(void *env, const char *fmt, ...) { |
|||
va_list args; |
|||
va_start(args, fmt); |
|||
vprintf(fmt, args); |
|||
va_end(args); |
|||
} |
|||
|
|||
void py_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, py_obj_t o_in) { |
|||
if (IS_SMALL_INT(o_in)) { |
|||
print(env, "%d", (int)FROM_SMALL_INT(o_in)); |
|||
} else { |
|||
py_obj_base_t *o = o_in; |
|||
switch (o->kind) { |
|||
case O_CONST: |
|||
print(env, "%s", o->id); |
|||
break; |
|||
case O_STR: |
|||
// TODO need to escape chars etc
|
|||
print(env, "'%s'", qstr_str(o->u_str)); |
|||
break; |
|||
#if MICROPY_ENABLE_FLOAT |
|||
case O_FLOAT: |
|||
print(env, "%.8g", o->u_float); |
|||
break; |
|||
case O_COMPLEX: |
|||
if (o->u_complex.real == 0) { |
|||
print(env, "%.8gj", o->u_complex.imag); |
|||
} else { |
|||
print(env, "(%.8g+%.8gj)", o->u_complex.real, o->u_complex.imag); |
|||
} |
|||
break; |
|||
#endif |
|||
case O_EXCEPTION_0: |
|||
print(env, "%s", qstr_str(o->u_exc0.id)); |
|||
break; |
|||
case O_EXCEPTION_N: |
|||
print(env, "%s: ", qstr_str(o->u_exc_n.id)); |
|||
print(env, o->u_exc_n.args[0], o->u_exc_n.args[1], o->u_exc_n.args[2]); |
|||
break; |
|||
case O_GEN_INSTANCE: |
|||
print(env, "<generator object 'fun-name' at %p>", o); |
|||
break; |
|||
case O_TUPLE: |
|||
print(env, "("); |
|||
for (int i = 0; i < o->u_tuple_list.len; i++) { |
|||
if (i > 0) { |
|||
print(env, ", "); |
|||
} |
|||
py_obj_print_helper(print, env, o->u_tuple_list.items[i]); |
|||
} |
|||
if (o->u_tuple_list.len == 1) { |
|||
print(env, ","); |
|||
} |
|||
print(env, ")"); |
|||
break; |
|||
case O_LIST: |
|||
print(env, "["); |
|||
for (int i = 0; i < o->u_tuple_list.len; i++) { |
|||
if (i > 0) { |
|||
print(env, ", "); |
|||
} |
|||
py_obj_print_helper(print, env, o->u_tuple_list.items[i]); |
|||
} |
|||
print(env, "]"); |
|||
break; |
|||
case O_SET: |
|||
{ |
|||
bool first = true; |
|||
print(env, "{"); |
|||
for (int i = 0; i < o->u_set.alloc; i++) { |
|||
if (o->u_set.table[i] != NULL) { |
|||
if (!first) { |
|||
print(env, ", "); |
|||
} |
|||
first = false; |
|||
py_obj_print_helper(print, env, o->u_set.table[i]); |
|||
} |
|||
} |
|||
print(env, "}"); |
|||
break; |
|||
} |
|||
case O_MAP: |
|||
{ |
|||
bool first = true; |
|||
print(env, "{"); |
|||
for (int i = 0; i < o->u_map.alloc; i++) { |
|||
if (o->u_map.table[i].key != NULL) { |
|||
if (!first) { |
|||
print(env, ", "); |
|||
} |
|||
first = false; |
|||
py_obj_print_helper(print, env, o->u_map.table[i].key); |
|||
print(env, ": "); |
|||
py_obj_print_helper(print, env, o->u_map.table[i].value); |
|||
} |
|||
} |
|||
print(env, "}"); |
|||
break; |
|||
} |
|||
case O_USER: |
|||
if (o->u_user.info->print == NULL) { |
|||
print(env, "<unknown user object>"); |
|||
} else { |
|||
o->u_user.info->print(o_in); |
|||
} |
|||
break; |
|||
default: |
|||
print(env, "<? %d>", o->kind); |
|||
assert(0); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void py_obj_print(py_obj_t o_in) { |
|||
py_obj_print_helper(printf_wrapper, NULL, o_in); |
|||
} |
|||
|
|||
bool py_obj_is_callable(py_obj_t o_in) { |
|||
if (IS_SMALL_INT(o_in)) { |
|||
return false; |
|||
} else { |
|||
py_obj_base_t *o = o_in; |
|||
switch (o->kind) { |
|||
case O_FUN_0: |
|||
case O_FUN_1: |
|||
case O_FUN_2: |
|||
case O_FUN_VAR: |
|||
case O_FUN_N: |
|||
case O_FUN_BC: |
|||
case O_FUN_ASM: |
|||
// what about O_CLASS, and an O_OBJ that has a __call__ method?
|
|||
return true; |
|||
default: |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
|
|||
machine_int_t py_obj_hash(py_obj_t o_in) { |
|||
if (o_in == py_const_false) { |
|||
return 0; // needs to hash to same as the integer 0, since False==0
|
|||
} else if (o_in == py_const_true) { |
|||
return 1; // needs to hash to same as the integer 1, since True==1
|
|||
} else if (IS_SMALL_INT(o_in)) { |
|||
return FROM_SMALL_INT(o_in); |
|||
} else if (IS_O(o_in, O_CONST)) { |
|||
return (machine_int_t)o_in; |
|||
} else if (IS_O(o_in, O_STR)) { |
|||
return ((py_obj_base_t*)o_in)->u_str; |
|||
} else { |
|||
assert(0); |
|||
return 0; |
|||
} |
|||
} |
|||
|
|||
// this function implements the '==' operator (and so the inverse of '!=')
|
|||
// from the python language reference:
|
|||
// "The objects need not have the same type. If both are numbers, they are converted
|
|||
// to a common type. Otherwise, the == and != operators always consider objects of
|
|||
// different types to be unequal."
|
|||
// note also that False==0 and True==1 are true expressions
|
|||
bool py_obj_equal(py_obj_t o1, py_obj_t o2) { |
|||
if (o1 == o2) { |
|||
return true; |
|||
} else if (IS_SMALL_INT(o1) || IS_SMALL_INT(o2)) { |
|||
if (IS_SMALL_INT(o1) && IS_SMALL_INT(o2)) { |
|||
return false; |
|||
} else { |
|||
if (IS_SMALL_INT(o2)) { |
|||
py_obj_t temp = o1; o1 = o2; o2 = temp; |
|||
} |
|||
// o1 is the SMALL_INT, o2 is not
|
|||
py_small_int_t val = FROM_SMALL_INT(o1); |
|||
if (o2 == py_const_false) { |
|||
return val == 0; |
|||
} else if (o2 == py_const_true) { |
|||
return val == 1; |
|||
} else { |
|||
return false; |
|||
} |
|||
} |
|||
} else if (IS_O(o1, O_STR) && IS_O(o2, O_STR)) { |
|||
return ((py_obj_base_t*)o1)->u_str == ((py_obj_base_t*)o2)->u_str; |
|||
} else { |
|||
assert(0); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
machine_int_t py_obj_get_int(py_obj_t arg) { |
|||
if (arg == py_const_false) { |
|||
return 0; |
|||
} else if (arg == py_const_true) { |
|||
return 1; |
|||
} else if (IS_SMALL_INT(arg)) { |
|||
return FROM_SMALL_INT(arg); |
|||
} else { |
|||
assert(0); |
|||
return 0; |
|||
} |
|||
} |
|||
|
|||
#if MICROPY_ENABLE_FLOAT |
|||
machine_float_t py_obj_get_float(py_obj_t arg) { |
|||
if (arg == py_const_false) { |
|||
return 0; |
|||
} else if (arg == py_const_true) { |
|||
return 1; |
|||
} else if (IS_SMALL_INT(arg)) { |
|||
return FROM_SMALL_INT(arg); |
|||
} else if (IS_O(arg, O_FLOAT)) { |
|||
return ((py_obj_base_t*)arg)->u_float; |
|||
} else { |
|||
assert(0); |
|||
return 0; |
|||
} |
|||
} |
|||
|
|||
void py_obj_get_complex(py_obj_t arg, py_float_t *real, py_float_t *imag) { |
|||
if (arg == py_const_false) { |
|||
*real = 0; |
|||
*imag = 0; |
|||
} else if (arg == py_const_true) { |
|||
*real = 1; |
|||
*imag = 0; |
|||
} else if (IS_SMALL_INT(arg)) { |
|||
*real = FROM_SMALL_INT(arg); |
|||
*imag = 0; |
|||
} else if (IS_O(arg, O_FLOAT)) { |
|||
*real = ((py_obj_base_t*)arg)->u_float; |
|||
*imag = 0; |
|||
} else if (IS_O(arg, O_COMPLEX)) { |
|||
*real = ((py_obj_base_t*)arg)->u_complex.real; |
|||
*imag = ((py_obj_base_t*)arg)->u_complex.imag; |
|||
} else { |
|||
assert(0); |
|||
*real = 0; |
|||
*imag = 0; |
|||
} |
|||
} |
|||
#endif |
|||
|
|||
qstr py_obj_get_qstr(py_obj_t arg) { |
|||
if (IS_O(arg, O_STR)) { |
|||
return ((py_obj_base_t*)arg)->u_str; |
|||
} else { |
|||
assert(0); |
|||
return 0; |
|||
} |
|||
} |
|||
|
|||
py_obj_t *py_obj_get_array_fixed_n(py_obj_t o_in, machine_int_t n) { |
|||
if (IS_O(o_in, O_TUPLE) || IS_O(o_in, O_LIST)) { |
|||
py_obj_base_t *o = o_in; |
|||
if (o->u_tuple_list.len != n) { |
|||
nlr_jump(py_obj_new_exception_2(rt_q_IndexError, "requested length %d but object has length %d", (void*)n, (void*)o->u_tuple_list.len)); |
|||
} |
|||
return o->u_tuple_list.items; |
|||
} else { |
|||
nlr_jump(py_obj_new_exception_2(rt_q_TypeError, "object '%s' is not a tuple or list", py_obj_get_type_str(o_in), NULL)); |
|||
} |
|||
} |
|||
|
|||
void py_user_get_data(py_obj_t o, machine_uint_t *data1, machine_uint_t *data2) { |
|||
assert(IS_O(o, O_USER)); |
|||
if (data1 != NULL) { |
|||
*data1 = ((py_obj_base_t*)o)->u_user.data1; |
|||
} |
|||
if (data2 != NULL) { |
|||
*data2 = ((py_obj_base_t*)o)->u_user.data2; |
|||
} |
|||
} |
|||
|
|||
void py_user_set_data(py_obj_t o, machine_uint_t data1, machine_uint_t data2) { |
|||
assert(IS_O(o, O_USER)); |
|||
((py_obj_base_t*)o)->u_user.data1 = data1; |
|||
((py_obj_base_t*)o)->u_user.data2 = data2; |
|||
} |
|||
|
|||
// temporary way of making C modules
|
|||
// hack: use class to mimic a module
|
|||
|
|||
py_obj_t py_module_new(void) { |
|||
py_obj_base_t *o = m_new(py_obj_base_t, 1); |
|||
o->kind = O_CLASS; |
|||
o->u_class.locals = py_map_new(MAP_QSTR, 0); |
|||
return o; |
|||
} |
@ -0,0 +1,55 @@ |
|||
typedef machine_int_t py_small_int_t; // do we need to expose this in the public API?
|
|||
|
|||
#if MICROPY_ENABLE_FLOAT |
|||
typedef machine_float_t py_float_t; |
|||
#endif |
|||
|
|||
// user defined objects
|
|||
|
|||
typedef struct _py_user_method_t { |
|||
const char *name; |
|||
machine_uint_t kind; |
|||
void *fun; |
|||
} py_user_method_t; |
|||
|
|||
typedef struct _py_user_info_t { |
|||
const char *type_name; |
|||
void (*print)(py_obj_t); |
|||
const py_user_method_t methods[]; |
|||
} py_user_info_t; |
|||
|
|||
py_obj_t py_obj_new_int(machine_int_t value); |
|||
py_obj_t py_obj_new_const(const char *id); |
|||
py_obj_t py_obj_new_str(qstr qstr); |
|||
#if MICROPY_ENABLE_FLOAT |
|||
py_obj_t py_obj_new_float(py_float_t val); |
|||
py_obj_t py_obj_new_complex(py_float_t real, py_float_t imag); |
|||
#endif |
|||
py_obj_t py_obj_new_exception_0(qstr id); |
|||
py_obj_t py_obj_new_exception_2(qstr id, const char *fmt, const char *s1, const char *s2); |
|||
py_obj_t py_obj_new_range(int start, int stop, int step); |
|||
py_obj_t py_obj_new_range_iterator(int cur, int stop, int step); |
|||
py_obj_t py_obj_new_user(const py_user_info_t *info, machine_uint_t data1, machine_uint_t data2); |
|||
|
|||
const char *py_obj_get_type_str(py_obj_t o_in); |
|||
|
|||
void py_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, py_obj_t o_in); |
|||
void py_obj_print(py_obj_t o); |
|||
|
|||
bool py_obj_is_callable(py_obj_t o_in); |
|||
machine_int_t py_obj_hash(py_obj_t o_in); |
|||
bool py_obj_equal(py_obj_t o1, py_obj_t o2); |
|||
|
|||
machine_int_t py_obj_get_int(py_obj_t arg); |
|||
#if MICROPY_ENABLE_FLOAT |
|||
machine_float_t py_obj_get_float(py_obj_t arg); |
|||
void py_obj_get_complex(py_obj_t arg, py_float_t *real, py_float_t *imag); |
|||
#endif |
|||
qstr py_obj_get_qstr(py_obj_t arg); |
|||
py_obj_t *py_obj_get_array_fixed_n(py_obj_t o, machine_int_t n); |
|||
|
|||
void py_user_get_data(py_obj_t o, machine_uint_t *data1, machine_uint_t *data2); |
|||
void py_user_set_data(py_obj_t o, machine_uint_t data1, machine_uint_t data2); |
|||
|
|||
// temporary way of making C modules
|
|||
py_obj_t py_module_new(void); |
@ -0,0 +1,140 @@ |
|||
// internal py_obj_t representation
|
|||
// not for general use, instead access using py_obj_xxx functions
|
|||
|
|||
#define IS_O(o, k) (((((py_small_int_t)(o)) & 1) == 0) && (((py_obj_base_t*)(o))->kind == (k))) |
|||
#define IS_SMALL_INT(o) (((py_small_int_t)(o)) & 1) |
|||
#define FROM_SMALL_INT(o) (((py_small_int_t)(o)) >> 1) |
|||
#define TO_SMALL_INT(o) ((py_obj_t)(((o) << 1) | 1)) |
|||
|
|||
typedef enum { |
|||
O_CONST, |
|||
O_STR, |
|||
#if MICROPY_ENABLE_FLOAT |
|||
O_FLOAT, |
|||
O_COMPLEX, |
|||
#endif |
|||
O_CELL, |
|||
O_EXCEPTION_0, |
|||
O_EXCEPTION_N, |
|||
O_RANGE, |
|||
O_RANGE_IT, |
|||
O_FUN_0, |
|||
O_FUN_1, |
|||
O_FUN_2, |
|||
O_FUN_N, |
|||
O_FUN_VAR, |
|||
O_FUN_BC, |
|||
O_FUN_ASM, |
|||
O_GEN_WRAP, |
|||
O_GEN_INSTANCE, |
|||
O_BOUND_METH, |
|||
O_CLOSURE, |
|||
O_TUPLE, |
|||
O_LIST, |
|||
O_TUPLE_IT, |
|||
O_LIST_IT, |
|||
O_SET, |
|||
O_MAP, |
|||
O_CLASS, |
|||
O_OBJ, |
|||
O_USER, |
|||
} py_obj_kind_t; |
|||
|
|||
typedef struct _py_obj_base_t py_obj_base_t; |
|||
|
|||
struct _py_obj_base_t { |
|||
py_obj_kind_t kind; |
|||
union { |
|||
const char *id; |
|||
qstr u_str; |
|||
#if MICROPY_ENABLE_FLOAT |
|||
py_float_t u_float; // for O_FLOAT
|
|||
struct { // for O_COMPLEX
|
|||
py_float_t real; |
|||
py_float_t imag; |
|||
} u_complex; |
|||
#endif |
|||
py_obj_t u_cell; // for O_CELL
|
|||
struct { // for O_EXCEPTION_0
|
|||
qstr id; |
|||
} u_exc0; |
|||
struct { // for O_EXCEPTION_N
|
|||
// TODO make generic object or something
|
|||
qstr id; |
|||
int n_args; |
|||
const void **args; |
|||
} u_exc_n; |
|||
struct { // for O_RANGE
|
|||
// TODO make generic object or something
|
|||
machine_int_t start; |
|||
machine_int_t stop; |
|||
machine_int_t step; |
|||
} u_range; |
|||
struct { // for O_RANGE_IT
|
|||
// TODO make generic object or something
|
|||
machine_int_t cur; |
|||
machine_int_t stop; |
|||
machine_int_t step; |
|||
} u_range_it; |
|||
struct { // for O_FUN_[012N], O_FUN_VAR
|
|||
int n_args; |
|||
void *fun; |
|||
} u_fun; |
|||
struct { // for O_FUN_BC
|
|||
int n_args; |
|||
uint n_state; |
|||
byte *code; |
|||
} u_fun_bc; |
|||
struct { // for O_FUN_ASM
|
|||
int n_args; |
|||
void *fun; |
|||
} u_fun_asm; |
|||
struct { // for O_GEN_WRAP
|
|||
int n_state; |
|||
py_obj_base_t *fun; |
|||
} u_gen_wrap; |
|||
struct { // for O_GEN_INSTANCE
|
|||
py_obj_t *state; |
|||
const byte *ip; |
|||
py_obj_t *sp; |
|||
} u_gen_instance; |
|||
struct { // for O_BOUND_METH
|
|||
py_obj_t meth; |
|||
py_obj_t self; |
|||
} u_bound_meth; |
|||
struct { // for O_CLOSURE
|
|||
py_obj_t fun; |
|||
py_obj_t vars; |
|||
} u_closure; |
|||
struct { // for O_TUPLE, O_LIST
|
|||
machine_uint_t alloc; |
|||
machine_uint_t len; |
|||
py_obj_t *items; |
|||
} u_tuple_list; |
|||
struct { // for O_TUPLE_IT, O_LIST_IT
|
|||
py_obj_base_t *obj; |
|||
machine_uint_t cur; |
|||
} u_tuple_list_it; |
|||
struct { // for O_SET
|
|||
machine_uint_t alloc; |
|||
machine_uint_t used; |
|||
py_obj_t *table; |
|||
} u_set; |
|||
py_map_t u_map; // for O_MAP
|
|||
struct { // for O_CLASS
|
|||
py_map_t *locals; |
|||
} u_class; |
|||
struct { // for O_OBJ
|
|||
py_obj_base_t *class; // points to a O_CLASS object
|
|||
py_map_t *members; |
|||
} u_obj; |
|||
struct { // for O_USER
|
|||
const py_user_info_t *info; |
|||
machine_uint_t data1; |
|||
machine_uint_t data2; |
|||
} u_user; |
|||
}; |
|||
}; |
|||
|
|||
py_obj_t py_obj_new_tuple_iterator(py_obj_base_t *tuple, int cur); |
|||
py_obj_t py_obj_new_list_iterator(py_obj_base_t *list, int cur); |
File diff suppressed because it is too large
Loading…
Reference in new issue