Skip to content

Commit 86c7fc7

Browse files
committed
py: add list pop and sort, unpack_sequence, and keywords in method_call.
1 parent 6f3e7fc commit 86c7fc7

File tree

2 files changed

+118
-21
lines changed

2 files changed

+118
-21
lines changed

py/runtime.c

Lines changed: 114 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ struct _py_obj_base_t {
179179
};
180180

181181
static qstr q_append;
182+
static qstr q_pop;
183+
static qstr q_sort;
182184
static qstr q_join;
183185
static qstr q_format;
184186
static qstr q___build_class__;
@@ -189,6 +191,7 @@ static qstr q_KeyError;
189191
static qstr q_NameError;
190192
static qstr q_TypeError;
191193
static qstr q_SyntaxError;
194+
static qstr q_ValueError;
192195

193196
py_obj_t py_const_none;
194197
py_obj_t py_const_false;
@@ -786,6 +789,24 @@ py_obj_t rt_str_format(int n_args, const py_obj_t* args) {
786789
return py_obj_new_str(qstr_from_str_take(vstr->buf));
787790
}
788791

792+
uint get_index(py_obj_base_t *base, py_obj_t index) {
793+
// assumes base is O_TUPLE or O_LIST
794+
// TODO False and True are considered 0 and 1 for indexing purposes
795+
int len = base->u_tuple_list.len;
796+
if (IS_SMALL_INT(index)) {
797+
int i = FROM_SMALL_INT(index);
798+
if (i < 0) {
799+
i += len;
800+
}
801+
if (i < 0 || i >= len) {
802+
nlr_jump(py_obj_new_exception_2(q_IndexError, "%s index out of range", py_obj_get_type_str(base), NULL));
803+
}
804+
return i;
805+
} else {
806+
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)));
807+
}
808+
}
809+
789810
py_obj_t rt_list_append(py_obj_t self_in, py_obj_t arg) {
790811
assert(IS_O(self_in, O_LIST));
791812
py_obj_base_t *self = self_in;
@@ -797,6 +818,47 @@ py_obj_t rt_list_append(py_obj_t self_in, py_obj_t arg) {
797818
return py_const_none; // return None, as per CPython
798819
}
799820

821+
py_obj_t rt_list_pop(py_obj_t self_in, py_obj_t arg) {
822+
assert(IS_O(self_in, O_LIST));
823+
py_obj_base_t *self = self_in;
824+
uint index = get_index(self, arg);
825+
py_obj_t ret = self->u_tuple_list.items[index];
826+
self->u_tuple_list.len -= 1;
827+
memcpy(self->u_tuple_list.items + index, self->u_tuple_list.items + index + 1, (self->u_tuple_list.len - index) * sizeof(py_obj_t));
828+
return ret;
829+
}
830+
831+
// TODO make this conform to CPython's definition of sort
832+
static void py_quicksort(py_obj_t *head, py_obj_t *tail, py_obj_t key_fn) {
833+
while (head < tail) {
834+
py_obj_t *h = head - 1;
835+
py_obj_t *t = tail;
836+
py_obj_t v = rt_call_function_1(key_fn, tail[0]); // get pivot using key_fn
837+
for (;;) {
838+
do ++h; while (rt_compare_op(RT_COMPARE_OP_LESS, rt_call_function_1(key_fn, h[0]), v) == py_const_true);
839+
do --t; while (h < t && rt_compare_op(RT_COMPARE_OP_LESS, v, rt_call_function_1(key_fn, t[0])) == py_const_true);
840+
if (h >= t) break;
841+
py_obj_t x = h[0];
842+
h[0] = t[0];
843+
t[0] = x;
844+
}
845+
py_obj_t x = h[0];
846+
h[0] = tail[0];
847+
tail[0] = x;
848+
py_quicksort(head, t, key_fn);
849+
head = h + 1;
850+
}
851+
}
852+
853+
py_obj_t rt_list_sort(py_obj_t self_in, py_obj_t key_fn) {
854+
assert(IS_O(self_in, O_LIST));
855+
py_obj_base_t *self = self_in;
856+
if (self->u_tuple_list.len > 1) {
857+
py_quicksort(self->u_tuple_list.items, self->u_tuple_list.items + self->u_tuple_list.len - 1, key_fn);
858+
}
859+
return py_const_none; // return None, as per CPython
860+
}
861+
800862
py_obj_t rt_gen_instance_next(py_obj_t self_in) {
801863
py_obj_t ret = rt_iternext(self_in);
802864
if (ret == py_const_stop_iteration) {
@@ -839,6 +901,8 @@ static py_code_t *unique_codes;
839901
py_obj_t fun_str_join;
840902
py_obj_t fun_str_format;
841903
py_obj_t fun_list_append;
904+
py_obj_t fun_list_pop;
905+
py_obj_t fun_list_sort;
842906
py_obj_t fun_gen_instance_next;
843907

844908
py_obj_t py_builtin___repl_print__(py_obj_t o) {
@@ -938,6 +1002,8 @@ FILE *fp_write_code = NULL;
9381002

9391003
void rt_init(void) {
9401004
q_append = qstr_from_str_static("append");
1005+
q_pop = qstr_from_str_static("pop");
1006+
q_sort = qstr_from_str_static("sort");
9411007
q_join = qstr_from_str_static("join");
9421008
q_format = qstr_from_str_static("format");
9431009
q___build_class__ = qstr_from_str_static("__build_class__");
@@ -948,6 +1014,7 @@ void rt_init(void) {
9481014
q_NameError = qstr_from_str_static("NameError");
9491015
q_TypeError = qstr_from_str_static("TypeError");
9501016
q_SyntaxError = qstr_from_str_static("SyntaxError");
1017+
q_ValueError = qstr_from_str_static("ValueError");
9511018

9521019
py_const_none = py_obj_new_const("None");
9531020
py_const_false = py_obj_new_const("False");
@@ -972,6 +1039,8 @@ void rt_init(void) {
9721039
fun_str_join = rt_make_function_2(rt_str_join);
9731040
fun_str_format = rt_make_function_var(1, rt_str_format);
9741041
fun_list_append = rt_make_function_2(rt_list_append);
1042+
fun_list_pop = rt_make_function_2(rt_list_pop);
1043+
fun_list_sort = rt_make_function_2(rt_list_sort);
9751044
fun_gen_instance_next = rt_make_function_1(rt_gen_instance_next);
9761045

9771046
#ifdef WRITE_CODE
@@ -1280,24 +1349,6 @@ py_obj_t rt_unary_op(int op, py_obj_t arg) {
12801349
return py_const_none;
12811350
}
12821351

1283-
uint get_index(py_obj_base_t *base, py_obj_t index) {
1284-
// assumes base is O_TUPLE or O_LIST
1285-
// TODO False and True are considered 0 and 1 for indexing purposes
1286-
int len = base->u_tuple_list.len;
1287-
if (IS_SMALL_INT(index)) {
1288-
int i = FROM_SMALL_INT(index);
1289-
if (i < 0) {
1290-
i += len;
1291-
}
1292-
if (i < 0 || i >= len) {
1293-
nlr_jump(py_obj_new_exception_2(q_IndexError, "%s index out of range", py_obj_get_type_str(base), NULL));
1294-
}
1295-
return i;
1296-
} else {
1297-
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)));
1298-
}
1299-
}
1300-
13011352
py_obj_t rt_binary_op(int op, py_obj_t lhs, py_obj_t rhs) {
13021353
DEBUG_OP_printf("binary %d %p %p\n", op, lhs, rhs);
13031354
if (op == RT_BINARY_OP_SUBSCR) {
@@ -1804,13 +1855,28 @@ py_obj_t rt_call_function_n(py_obj_t fun, int n_args, const py_obj_t *args) {
18041855
nlr_jump(py_obj_new_exception_2(q_TypeError, "function takes %d positional arguments but %d were given", (const char*)(machine_int_t)n_args_fun, (const char*)(machine_int_t)n_args));
18051856
}
18061857

1858+
// args are in reverse order in the array; keyword arguments come first, value then key
1859+
// eg: (value1, key1, value0, key0, arg1, arg0)
1860+
py_obj_t rt_call_function_n_kw(py_obj_t fun, uint n_args, uint n_kw, const py_obj_t *args) {
1861+
// TODO
1862+
assert(0);
1863+
return py_const_none;
1864+
}
1865+
18071866
// args contains: arg(n_args-1) arg(n_args-2) ... arg(0) self/NULL fun
18081867
// if n_args==0 then there are only self/NULL and fun
1809-
py_obj_t rt_call_method_n(int n_args, const py_obj_t *args) {
1810-
DEBUG_OP_printf("call method %p(self=%p, n_args=%d)\n", args[n_args + 1], args[n_args], n_args);
1868+
py_obj_t rt_call_method_n(uint n_args, const py_obj_t *args) {
1869+
DEBUG_OP_printf("call method %p(self=%p, n_args=%u)\n", args[n_args + 1], args[n_args], n_args);
18111870
return rt_call_function_n(args[n_args + 1], n_args + ((args[n_args] == NULL) ? 0 : 1), args);
18121871
}
18131872

1873+
// args contains: kw_val(n_kw-1) kw_key(n_kw-1) ... kw_val(0) kw_key(0) arg(n_args-1) arg(n_args-2) ... arg(0) self/NULL fun
1874+
py_obj_t rt_call_method_n_kw(uint n_args, uint n_kw, const py_obj_t *args) {
1875+
uint n = n_args + 2 * n_kw;
1876+
DEBUG_OP_printf("call method %p(self=%p, n_args=%u, n_kw=%u)\n", args[n + 1], args[n], n_args, n_kw);
1877+
return rt_call_function_n_kw(args[n + 1], n_args + ((args[n] == NULL) ? 0 : 1), n_kw, args);
1878+
}
1879+
18141880
// items are in reverse order
18151881
py_obj_t rt_build_tuple(int n_args, py_obj_t *items) {
18161882
py_obj_base_t *o = m_new(py_obj_base_t, 1);
@@ -1900,6 +1966,22 @@ py_obj_t rt_store_set(py_obj_t set, py_obj_t item) {
19001966
return set;
19011967
}
19021968

1969+
// unpacked items are stored in order into the array pointed to by items
1970+
void rt_unpack_sequence(py_obj_t seq_in, uint num, py_obj_t *items) {
1971+
if (IS_O(seq_in, O_TUPLE) || IS_O(seq_in, O_LIST)) {
1972+
py_obj_base_t *seq = seq_in;
1973+
if (seq->u_tuple_list.len < num) {
1974+
nlr_jump(py_obj_new_exception_2(q_ValueError, "need more than %d values to unpack", (void*)seq->u_tuple_list.len, NULL));
1975+
} else if (seq->u_tuple_list.len > num) {
1976+
nlr_jump(py_obj_new_exception_2(q_ValueError, "too many values to unpack (expected %d)", (void*)(machine_uint_t)num, NULL));
1977+
}
1978+
memcpy(items, seq->u_tuple_list.items, num * sizeof(py_obj_t));
1979+
} else {
1980+
// TODO call rt_getiter and extract via rt_iternext
1981+
nlr_jump(py_obj_new_exception_2(q_TypeError, "'%s' object is not iterable", py_obj_get_type_str(seq_in), NULL));
1982+
}
1983+
}
1984+
19031985
py_obj_t rt_build_map(int n_args) {
19041986
py_obj_base_t *o = m_new(py_obj_base_t, 1);
19051987
o->kind = O_MAP;
@@ -1925,6 +2007,10 @@ py_obj_t rt_load_attr(py_obj_t base, qstr attr) {
19252007
DEBUG_OP_printf("load attr %s\n", qstr_str(attr));
19262008
if (IS_O(base, O_LIST) && attr == q_append) {
19272009
return build_bound_method(base, fun_list_append);
2010+
} else if (IS_O(base, O_LIST) && attr == q_pop) {
2011+
return build_bound_method(base, fun_list_pop);
2012+
} else if (IS_O(base, O_LIST) && attr == q_sort) {
2013+
return build_bound_method(base, fun_list_sort);
19282014
} else if (IS_O(base, O_CLASS)) {
19292015
py_obj_base_t *o = base;
19302016
py_map_elem_t *elem = py_qstr_map_lookup(o->u_class.locals, attr, false);
@@ -1977,6 +2063,14 @@ void rt_load_method(py_obj_t base, qstr attr, py_obj_t *dest) {
19772063
dest[1] = fun_list_append;
19782064
dest[0] = base;
19792065
return;
2066+
} else if (IS_O(base, O_LIST) && attr == q_pop) {
2067+
dest[1] = fun_list_pop;
2068+
dest[0] = base;
2069+
return;
2070+
} else if (IS_O(base, O_LIST) && attr == q_sort) {
2071+
dest[1] = fun_list_sort;
2072+
dest[0] = base;
2073+
return;
19802074
} else if (IS_O(base, O_OBJ)) {
19812075
// logic: look in obj members then class locals (TODO check this against CPython)
19822076
py_obj_base_t *o = base;

py/runtime.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,12 +128,15 @@ py_obj_t rt_call_function_0(py_obj_t fun);
128128
py_obj_t rt_call_function_1(py_obj_t fun, py_obj_t arg);
129129
py_obj_t rt_call_function_2(py_obj_t fun, py_obj_t arg1, py_obj_t arg2);
130130
py_obj_t rt_call_function_n(py_obj_t fun, int n_args, const py_obj_t *args);
131-
py_obj_t rt_call_method_n(int n_args, const py_obj_t *args);
131+
py_obj_t rt_call_function_n_kw(py_obj_t fun, uint n_args, uint n_kw, const py_obj_t *args);
132+
py_obj_t rt_call_method_n(uint n_args, const py_obj_t *args);
133+
py_obj_t rt_call_method_n_kw(uint n_args, uint n_kw, const py_obj_t *args);
132134
py_obj_t rt_build_tuple(int n_args, py_obj_t *items);
133135
py_obj_t rt_build_list(int n_args, py_obj_t *items);
134136
py_obj_t rt_list_append(py_obj_t list, py_obj_t arg);
135137
py_obj_t rt_build_set(int n_args, py_obj_t *items);
136138
py_obj_t rt_store_set(py_obj_t set, py_obj_t item);
139+
void rt_unpack_sequence(py_obj_t seq, uint num, py_obj_t *items);
137140
py_obj_t rt_build_map(int n_args);
138141
py_obj_t rt_store_map(py_obj_t map, py_obj_t key, py_obj_t value);
139142
py_obj_t rt_load_attr(py_obj_t base, qstr attr);

0 commit comments

Comments
 (0)