Support tuples and list comprehension, albeit crude.
This commit is contained in:
parent
152568bcb6
commit
c226dca1f7
160
py/runtime.c
160
py/runtime.c
@ -1,3 +1,6 @@
|
||||
// in principle, rt_xxx functions are called only by vm/native/viper and make assumptions about args
|
||||
// py_xxx functions are safer and can be called by anyone
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@ -48,7 +51,10 @@ typedef enum {
|
||||
O_FUN_BC,
|
||||
O_FUN_ASM,
|
||||
O_BOUND_METH,
|
||||
O_TUPLE,
|
||||
O_LIST,
|
||||
O_TUPLE_IT,
|
||||
O_LIST_IT,
|
||||
O_SET,
|
||||
O_MAP,
|
||||
O_CLASS,
|
||||
@ -121,11 +127,15 @@ struct _py_obj_base_t {
|
||||
py_obj_t meth;
|
||||
py_obj_t self;
|
||||
} u_bound_meth;
|
||||
struct { // for O_LIST
|
||||
struct { // for O_TUPLE, O_LIST
|
||||
int alloc;
|
||||
int len;
|
||||
py_obj_t *items;
|
||||
} u_list;
|
||||
} u_tuple_list;
|
||||
struct { // for O_TUPLE_IT, O_LIST_IT
|
||||
py_obj_base_t *obj;
|
||||
int cur;
|
||||
} u_tuple_list_it;
|
||||
struct { // for O_SET
|
||||
int alloc;
|
||||
int used;
|
||||
@ -330,14 +340,30 @@ py_obj_t py_obj_new_range_iterator(int cur, int stop, int step) {
|
||||
return o;
|
||||
}
|
||||
|
||||
py_obj_t list_append(py_obj_t self_in, py_obj_t arg) {
|
||||
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 rt_list_append(py_obj_t self_in, py_obj_t arg) {
|
||||
assert(IS_O(self_in, O_LIST));
|
||||
py_obj_base_t *self = self_in;
|
||||
if (self->u_list.len >= self->u_list.alloc) {
|
||||
self->u_list.alloc *= 2;
|
||||
self->u_list.items = m_renew(py_obj_t, self->u_list.items, self->u_list.alloc);
|
||||
if (self->u_tuple_list.len >= self->u_tuple_list.alloc) {
|
||||
self->u_tuple_list.alloc *= 2;
|
||||
self->u_tuple_list.items = m_renew(py_obj_t, self->u_tuple_list.items, self->u_tuple_list.alloc);
|
||||
}
|
||||
self->u_list.items[self->u_list.len++] = arg;
|
||||
self->u_tuple_list.items[self->u_tuple_list.len++] = arg;
|
||||
return arg;
|
||||
}
|
||||
|
||||
@ -346,6 +372,7 @@ static qstr q_print;
|
||||
static qstr q_len;
|
||||
static qstr q___build_class__;
|
||||
static qstr q_AttributeError;
|
||||
static qstr q_IndexError;
|
||||
static qstr q_NameError;
|
||||
static qstr q_TypeError;
|
||||
|
||||
@ -392,9 +419,9 @@ py_obj_t py_builtin_print(py_obj_t o) {
|
||||
|
||||
py_obj_t py_builtin_len(py_obj_t o_in) {
|
||||
py_small_int_t len = 0;
|
||||
if (IS_O(o_in, O_LIST)) {
|
||||
if (IS_O(o_in, O_TUPLE) || IS_O(o_in, O_LIST)) {
|
||||
py_obj_base_t *o = o_in;
|
||||
len = o->u_list.len;
|
||||
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;
|
||||
@ -437,6 +464,7 @@ void rt_init() {
|
||||
q_len = qstr_from_str_static("len");
|
||||
q___build_class__ = qstr_from_str_static("__build_class__");
|
||||
q_AttributeError = qstr_from_str_static("AttributeError");
|
||||
q_IndexError = qstr_from_str_static("IndexError");
|
||||
q_NameError = qstr_from_str_static("NameError");
|
||||
q_TypeError = qstr_from_str_static("TypeError");
|
||||
|
||||
@ -458,7 +486,7 @@ void rt_init() {
|
||||
next_unique_code_id = 1;
|
||||
unique_codes = NULL;
|
||||
|
||||
fun_list_append = rt_make_function_2(list_append);
|
||||
fun_list_append = rt_make_function_2(rt_list_append);
|
||||
|
||||
#ifdef WRITE_NATIVE
|
||||
fp_native = fopen("out-native", "wb");
|
||||
@ -597,8 +625,14 @@ const char *py_obj_get_type_str(py_obj_t o_in) {
|
||||
case O_FUN_N:
|
||||
case O_FUN_BC:
|
||||
return "function";
|
||||
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:
|
||||
@ -639,13 +673,26 @@ void py_obj_print(py_obj_t o_in) {
|
||||
printf("%s: ", qstr_str(o->u_exc2.id));
|
||||
printf(o->u_exc2.fmt, o->u_exc2.s1, o->u_exc2.s2);
|
||||
break;
|
||||
case O_LIST:
|
||||
printf("[");
|
||||
for (int i = 0; i < o->u_list.len; i++) {
|
||||
case O_TUPLE:
|
||||
printf("(");
|
||||
for (int i = 0; i < o->u_tuple_list.len; i++) {
|
||||
if (i > 0) {
|
||||
printf(", ");
|
||||
}
|
||||
py_obj_print(o->u_list.items[i]);
|
||||
py_obj_print(o->u_tuple_list.items[i]);
|
||||
}
|
||||
if (o->u_tuple_list.len == 1) {
|
||||
printf(",");
|
||||
}
|
||||
printf(")");
|
||||
break;
|
||||
case O_LIST:
|
||||
printf("[");
|
||||
for (int i = 0; i < o->u_tuple_list.len; i++) {
|
||||
if (i > 0) {
|
||||
printf(", ");
|
||||
}
|
||||
py_obj_print(o->u_tuple_list.items[i]);
|
||||
}
|
||||
printf("]");
|
||||
break;
|
||||
@ -711,7 +758,11 @@ int rt_is_true(py_obj_t arg) {
|
||||
}
|
||||
|
||||
int rt_get_int(py_obj_t arg) {
|
||||
if (IS_SMALL_INT(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);
|
||||
@ -778,11 +829,30 @@ py_obj_t rt_unary_op(int op, py_obj_t arg) {
|
||||
return py_const_none;
|
||||
}
|
||||
|
||||
uint get_index(py_obj_base_t *base, py_obj_t index) {
|
||||
// assumes base is O_TUPLE or O_LIST
|
||||
// TODO False and True are considered 0 and 1 for indexing purposes
|
||||
int len = base->u_tuple_list.len;
|
||||
if (IS_SMALL_INT(index)) {
|
||||
int i = FROM_SMALL_INT(index);
|
||||
if (i < 0) {
|
||||
i += len;
|
||||
}
|
||||
if (i < 0 || i >= len) {
|
||||
nlr_jump(py_obj_new_exception_2(q_IndexError, "%s index out of range", py_obj_get_type_str(base), NULL));
|
||||
}
|
||||
return i;
|
||||
} else {
|
||||
nlr_jump(py_obj_new_exception_2(q_TypeError, "%s indices must be integers, not %s", py_obj_get_type_str(base), py_obj_get_type_str(index)));
|
||||
}
|
||||
}
|
||||
|
||||
py_obj_t rt_binary_op(int op, py_obj_t lhs, py_obj_t rhs) {
|
||||
DEBUG_OP_printf("binary %d %p %p\n", op, lhs, rhs);
|
||||
if (op == RT_BINARY_OP_SUBSCR) {
|
||||
if (IS_O(lhs, O_LIST) && IS_SMALL_INT(rhs)) {
|
||||
return ((py_obj_base_t*)lhs)->u_list.items[FROM_SMALL_INT(rhs)];
|
||||
if ((IS_O(lhs, O_TUPLE) || IS_O(lhs, O_LIST))) {
|
||||
uint index = get_index(lhs, rhs);
|
||||
return ((py_obj_base_t*)lhs)->u_tuple_list.items[index];
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
@ -945,9 +1015,10 @@ machine_uint_t rt_convert_obj_for_inline_asm(py_obj_t obj) {
|
||||
return (machine_int_t)o->u_flt;
|
||||
#endif
|
||||
|
||||
case O_TUPLE:
|
||||
case O_LIST:
|
||||
// pointer to start of list (could pass length, but then could use len(x) for that)
|
||||
return (machine_uint_t)o->u_list.items;
|
||||
// pointer to start of tuple/list (could pass length, but then could use len(x) for that)
|
||||
return (machine_uint_t)o->u_tuple_list.items;
|
||||
|
||||
default:
|
||||
// just pass along a pointer to the object
|
||||
@ -1073,18 +1144,28 @@ py_obj_t rt_call_method_n(int n_args, const py_obj_t *args) {
|
||||
return rt_call_function_n(args[n_args + 1], n_args + ((args[n_args] == NULL) ? 0 : 1), args);
|
||||
}
|
||||
|
||||
// items are in reverse order
|
||||
py_obj_t rt_build_tuple(int n_args, py_obj_t *items) {
|
||||
py_obj_base_t *o = m_new(py_obj_base_t, 1);
|
||||
o->kind = O_TUPLE;
|
||||
o->u_tuple_list.alloc = n_args < 4 ? 4 : n_args;
|
||||
o->u_tuple_list.len = n_args;
|
||||
o->u_tuple_list.items = m_new(py_obj_t, o->u_tuple_list.alloc);
|
||||
for (int i = 0; i < n_args; i++) {
|
||||
o->u_tuple_list.items[i] = items[n_args - i - 1];
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
// items are in reverse order
|
||||
py_obj_t rt_build_list(int n_args, py_obj_t *items) {
|
||||
py_obj_base_t *o = m_new(py_obj_base_t, 1);
|
||||
o->kind = O_LIST;
|
||||
o->u_list.alloc = n_args;
|
||||
if (o->u_list.alloc < 4) {
|
||||
o->u_list.alloc = 4;
|
||||
}
|
||||
o->u_list.len = n_args;
|
||||
o->u_list.items = m_new(py_obj_t, o->u_list.alloc);
|
||||
o->u_tuple_list.alloc = n_args < 4 ? 4 : n_args;
|
||||
o->u_tuple_list.len = n_args;
|
||||
o->u_tuple_list.items = m_new(py_obj_t, o->u_tuple_list.alloc);
|
||||
for (int i = 0; i < n_args; i++) {
|
||||
o->u_list.items[i] = items[n_args - i - 1];
|
||||
o->u_tuple_list.items[i] = items[n_args - i - 1];
|
||||
}
|
||||
return o;
|
||||
}
|
||||
@ -1260,18 +1341,10 @@ void rt_store_attr(py_obj_t base, qstr attr, py_obj_t val) {
|
||||
}
|
||||
|
||||
void rt_store_subscr(py_obj_t base, py_obj_t index, py_obj_t value) {
|
||||
if (IS_O(base, O_LIST) && IS_SMALL_INT(index)) {
|
||||
if (IS_O(base, O_LIST)) {
|
||||
// list store
|
||||
py_obj_base_t *o = base;
|
||||
int idx = FROM_SMALL_INT(index);
|
||||
if (idx < 0) {
|
||||
idx += o->u_list.len;
|
||||
}
|
||||
if (0 <= idx && idx < o->u_list.len) {
|
||||
o->u_list.items[idx] = value;
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
uint i = get_index(base, index);
|
||||
((py_obj_base_t*)base)->u_tuple_list.items[i] = value;
|
||||
} else if (IS_O(base, O_MAP)) {
|
||||
// map store
|
||||
py_map_lookup(base, index, true)->value = value;
|
||||
@ -1284,6 +1357,10 @@ py_obj_t rt_getiter(py_obj_t o_in) {
|
||||
if (IS_O(o_in, O_RANGE)) {
|
||||
py_obj_base_t *o = o_in;
|
||||
return py_obj_new_range_iterator(o->u_range.start, o->u_range.stop, o->u_range.step);
|
||||
} else if (IS_O(o_in, O_TUPLE)) {
|
||||
return py_obj_new_tuple_iterator(o_in, 0);
|
||||
} else if (IS_O(o_in, O_LIST)) {
|
||||
return py_obj_new_list_iterator(o_in, 0);
|
||||
} else {
|
||||
nlr_jump(py_obj_new_exception_2(q_TypeError, "'%s' object is not iterable", py_obj_get_type_str(o_in), NULL));
|
||||
}
|
||||
@ -1299,6 +1376,15 @@ py_obj_t rt_iternext(py_obj_t o_in) {
|
||||
} else {
|
||||
return py_const_stop_iteration;
|
||||
}
|
||||
} else if (IS_O(o_in, O_TUPLE_IT) || IS_O(o_in, O_LIST_IT)) {
|
||||
py_obj_base_t *o = o_in;
|
||||
if (o->u_tuple_list_it.cur < o->u_tuple_list_it.obj->u_tuple_list.len) {
|
||||
py_obj_t o_out = o->u_tuple_list_it.obj->u_tuple_list.items[o->u_tuple_list_it.cur];
|
||||
o->u_tuple_list_it.cur += 1;
|
||||
return o_out;
|
||||
} else {
|
||||
return py_const_stop_iteration;
|
||||
}
|
||||
} else {
|
||||
nlr_jump(py_obj_new_exception_2(q_TypeError, "? '%s' object is not iterable", py_obj_get_type_str(o_in), NULL));
|
||||
}
|
||||
|
@ -116,7 +116,9 @@ py_obj_t rt_call_function_n(py_obj_t fun, int n_args, const py_obj_t *args);
|
||||
py_obj_t rt_call_method_1(py_obj_t fun, py_obj_t self);
|
||||
py_obj_t rt_call_method_2(py_obj_t fun, py_obj_t self, py_obj_t arg);
|
||||
py_obj_t rt_call_method_n(int n_args, const py_obj_t *args);
|
||||
py_obj_t rt_build_tuple(int n_args, py_obj_t *items);
|
||||
py_obj_t rt_build_list(int n_args, py_obj_t *items);
|
||||
py_obj_t rt_list_append(py_obj_t list, py_obj_t arg);
|
||||
py_obj_t rt_build_map(int n_args);
|
||||
py_obj_t rt_store_map(py_obj_t map, py_obj_t key, py_obj_t value);
|
||||
py_obj_t rt_build_set(int n_args, py_obj_t *items);
|
||||
|
14
py/vm.c
14
py/vm.c
@ -268,6 +268,13 @@ py_obj_t py_execute_byte_code(const byte *code, uint len, const py_obj_t *args,
|
||||
*sp = rt_compare_op(unum, obj1, obj2);
|
||||
break;
|
||||
|
||||
case PYBC_BUILD_TUPLE:
|
||||
DECODE_UINT;
|
||||
obj1 = rt_build_tuple(unum, sp);
|
||||
sp += unum - 1;
|
||||
*sp = obj1;
|
||||
break;
|
||||
|
||||
case PYBC_BUILD_LIST:
|
||||
DECODE_UINT;
|
||||
obj1 = rt_build_list(unum, sp);
|
||||
@ -275,6 +282,13 @@ py_obj_t py_execute_byte_code(const byte *code, uint len, const py_obj_t *args,
|
||||
*sp = obj1;
|
||||
break;
|
||||
|
||||
case PYBC_LIST_APPEND:
|
||||
DECODE_UINT;
|
||||
// I think it's guaranteed by the compiler that sp[unum] is a list
|
||||
rt_list_append(sp[unum], sp[0]);
|
||||
sp++;
|
||||
break;
|
||||
|
||||
case PYBC_BUILD_MAP:
|
||||
DECODE_UINT;
|
||||
PUSH(rt_build_map(unum));
|
||||
|
Loading…
x
Reference in New Issue
Block a user