Skip to content

Commit a3dcd9e

Browse files
committed
py: add more Python built-in functions.
1 parent 8c3da5c commit a3dcd9e

File tree

6 files changed

+356
-69
lines changed

6 files changed

+356
-69
lines changed

py/builtin.c

Lines changed: 281 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,35 @@
1616
#include "objprivate.h"
1717
#include "builtin.h"
1818

19+
py_obj_t py_builtin___build_class__(py_obj_t o_class_fun, py_obj_t o_class_name) {
20+
// we differ from CPython: we set the new __locals__ object here
21+
py_map_t *old_locals = rt_get_map_locals();
22+
py_map_t *class_locals = py_map_new(MAP_QSTR, 0);
23+
rt_set_map_locals(class_locals);
24+
25+
// call the class code
26+
rt_call_function_1(o_class_fun, (py_obj_t)0xdeadbeef);
27+
28+
// restore old __locals__ object
29+
rt_set_map_locals(old_locals);
30+
31+
// create and return the new class
32+
py_obj_base_t *o = m_new(py_obj_base_t, 1);
33+
o->kind = O_CLASS;
34+
o->u_class.locals = class_locals;
35+
return o;
36+
}
37+
38+
py_obj_t py_builtin___import__(int n, py_obj_t *args) {
39+
printf("import:\n");
40+
for (int i = 0; i < n; i++) {
41+
printf(" ");
42+
py_obj_print(args[i]);
43+
printf("\n");
44+
}
45+
return py_const_none;
46+
}
47+
1948
py_obj_t py_builtin___repl_print__(py_obj_t o) {
2049
if (o != py_const_none) {
2150
py_obj_print(o);
@@ -24,21 +53,150 @@ py_obj_t py_builtin___repl_print__(py_obj_t o) {
2453
return py_const_none;
2554
}
2655

27-
py_obj_t py_builtin_print(int n_args, const py_obj_t* args) {
28-
for (int i = 0; i < n_args; i++) {
29-
if (i > 0) {
30-
printf(" ");
56+
py_obj_t py_builtin_abs(py_obj_t o_in) {
57+
if (IS_SMALL_INT(o_in)) {
58+
py_small_int_t val = FROM_SMALL_INT(o_in);
59+
if (val < 0) {
60+
val = -val;
3161
}
32-
if (IS_O(args[i], O_STR)) {
33-
// special case, print string raw
34-
printf("%s", qstr_str(((py_obj_base_t*)args[i])->u_str));
62+
return TO_SMALL_INT(val);
63+
#if MICROPY_ENABLE_FLOAT
64+
} else if (IS_O(o_in, O_FLOAT)) {
65+
py_obj_base_t *o = o_in;
66+
// TODO check for NaN etc
67+
if (o->u_float < 0) {
68+
return py_obj_new_float(-o->u_float);
3569
} else {
36-
// print the object Python style
37-
py_obj_print(args[i]);
70+
return o_in;
3871
}
72+
} else if (IS_O(o_in, O_COMPLEX)) {
73+
py_obj_base_t *o = o_in;
74+
return py_obj_new_float(machine_sqrt(o->u_complex.real*o->u_complex.real + o->u_complex.imag*o->u_complex.imag));
75+
#endif
76+
} else {
77+
assert(0);
78+
return py_const_none;
79+
}
80+
}
81+
82+
py_obj_t py_builtin_all(py_obj_t o_in) {
83+
py_obj_t iterable = rt_getiter(o_in);
84+
py_obj_t item;
85+
while ((item = rt_iternext(iterable)) != py_const_stop_iteration) {
86+
if (!rt_is_true(item)) {
87+
return py_const_false;
88+
}
89+
}
90+
return py_const_true;
91+
}
92+
93+
py_obj_t py_builtin_any(py_obj_t o_in) {
94+
py_obj_t iterable = rt_getiter(o_in);
95+
py_obj_t item;
96+
while ((item = rt_iternext(iterable)) != py_const_stop_iteration) {
97+
if (rt_is_true(item)) {
98+
return py_const_true;
99+
}
100+
}
101+
return py_const_false;
102+
}
103+
104+
py_obj_t py_builtin_bool(int n_args, const py_obj_t *args) {
105+
switch (n_args) {
106+
case 0: return py_const_false;
107+
case 1: if (rt_is_true(args[0])) { return py_const_true; } else { return py_const_false; }
108+
default: nlr_jump(py_obj_new_exception_2(rt_q_TypeError, "bool() takes at most 1 argument (%d given)", (void*)(machine_int_t)n_args, NULL));
109+
}
110+
}
111+
112+
py_obj_t py_builtin_callable(py_obj_t o_in) {
113+
if (py_obj_is_callable(o_in)) {
114+
return py_const_true;
115+
} else {
116+
return py_const_false;
117+
}
118+
}
119+
120+
#if MICROPY_ENABLE_FLOAT
121+
py_obj_t py_builtin_complex(int n_args, const py_obj_t *args) {
122+
switch (n_args) {
123+
case 0:
124+
return py_obj_new_complex(0, 0);
125+
126+
case 1:
127+
// TODO allow string as first arg
128+
if (IS_O(args[0], O_COMPLEX)) {
129+
return args[0];
130+
} else {
131+
return py_obj_new_complex(py_obj_get_float(args[0]), 0);
132+
}
133+
134+
case 2:
135+
{
136+
py_float_t real, imag;
137+
if (IS_O(args[0], O_COMPLEX)) {
138+
py_obj_get_complex(args[0], &real, &imag);
139+
} else {
140+
real = py_obj_get_float(args[0]);
141+
imag = 0;
142+
}
143+
if (IS_O(args[1], O_COMPLEX)) {
144+
py_float_t real2, imag2;
145+
py_obj_get_complex(args[1], &real2, &imag2);
146+
real -= imag2;
147+
imag += real2;
148+
} else {
149+
imag += py_obj_get_float(args[1]);
150+
}
151+
return py_obj_new_complex(real, imag);
152+
}
153+
154+
default: nlr_jump(py_obj_new_exception_2(rt_q_TypeError, "comlpex() takes at most 2 arguments (%d given)", (void*)(machine_int_t)n_args, NULL));
155+
}
156+
}
157+
#endif
158+
159+
py_obj_t py_builtin_chr(py_obj_t o_in) {
160+
int ord = py_obj_get_int(o_in);
161+
if (0 <= ord && ord <= 0x10ffff) {
162+
char *str = m_new(char, 2);
163+
str[0] = ord;
164+
str[1] = '\0';
165+
return py_obj_new_str(qstr_from_str_take(str));
166+
} else {
167+
nlr_jump(py_obj_new_exception_2(rt_q_ValueError, "chr() arg not in range(0x110000)", NULL, NULL));
39168
}
40-
printf("\n");
41-
return py_const_none;
169+
}
170+
171+
py_obj_t py_builtin_dict(void) {
172+
// TODO create from an iterable!
173+
return rt_build_map(0);
174+
}
175+
176+
py_obj_t py_builtin_divmod(py_obj_t o1_in, py_obj_t o2_in) {
177+
if (IS_SMALL_INT(o1_in) && IS_SMALL_INT(o2_in)) {
178+
py_small_int_t i1 = FROM_SMALL_INT(o1_in);
179+
py_small_int_t i2 = FROM_SMALL_INT(o2_in);
180+
py_obj_t revs_args[2];
181+
revs_args[1] = TO_SMALL_INT(i1 / i2);
182+
revs_args[0] = TO_SMALL_INT(i1 % i2);
183+
return rt_build_tuple(2, revs_args);
184+
} else {
185+
nlr_jump(py_obj_new_exception_2(rt_q_TypeError, "unsupported operand type(s) for divmod(): '%s' and '%s'", py_obj_get_type_str(o1_in), py_obj_get_type_str(o2_in)));
186+
}
187+
}
188+
189+
py_obj_t py_builtin_hash(py_obj_t o_in) {
190+
// TODO hash will generally overflow small integer; can we safely truncate it?
191+
return py_obj_new_int(py_obj_hash(o_in));
192+
}
193+
194+
py_obj_t py_builtin_iter(py_obj_t o_in) {
195+
return rt_getiter(o_in);
196+
}
197+
198+
py_obj_t py_builtin_next(py_obj_t o_in) {
199+
return rt_gen_instance_next(o_in);
42200
}
43201

44202
py_obj_t py_builtin_len(py_obj_t o_in) {
@@ -53,61 +211,137 @@ py_obj_t py_builtin_len(py_obj_t o_in) {
53211
py_obj_base_t *o = o_in;
54212
len = o->u_map.used;
55213
} else {
56-
assert(0);
214+
nlr_jump(py_obj_new_exception_2(rt_q_TypeError, "object of type '%s' has no len()", py_obj_get_type_str(o_in), NULL));
57215
}
58216
return TO_SMALL_INT(len);
59217
}
60218

61-
py_obj_t py_builtin_abs(py_obj_t o_in) {
62-
if (IS_SMALL_INT(o_in)) {
63-
py_small_int_t val = FROM_SMALL_INT(o_in);
64-
if (val < 0) {
65-
val = -val;
219+
py_obj_t py_builtin_list(int n_args, const py_obj_t *args) {
220+
switch (n_args) {
221+
case 0: return rt_build_list(0, NULL);
222+
case 1:
223+
{
224+
// make list from iterable
225+
py_obj_t iterable = rt_getiter(args[0]);
226+
py_obj_t list = rt_build_list(0, NULL);
227+
py_obj_t item;
228+
while ((item = rt_iternext(iterable)) != py_const_stop_iteration) {
229+
rt_list_append(list, item);
230+
}
231+
return list;
66232
}
67-
return TO_SMALL_INT(val);
68-
#if MICROPY_ENABLE_FLOAT
69-
} else if (IS_O(o_in, O_FLOAT)) {
70-
py_obj_base_t *o = o_in;
71-
// TODO check for NaN etc
72-
if (o->u_float < 0) {
73-
return py_obj_new_float(-o->u_float);
74-
} else {
75-
return o_in;
233+
default: nlr_jump(py_obj_new_exception_2(rt_q_TypeError, "list() takes at most 1 argument (%d given)", (void*)(machine_int_t)n_args, NULL));
234+
}
235+
}
236+
237+
py_obj_t py_builtin_max(int n_args, const py_obj_t *args) {
238+
if (n_args == 1) {
239+
// given an iterable
240+
py_obj_t iterable = rt_getiter(args[0]);
241+
py_obj_t max_obj = NULL;
242+
py_obj_t item;
243+
while ((item = rt_iternext(iterable)) != py_const_stop_iteration) {
244+
if (max_obj == NULL || py_obj_less(max_obj, item)) {
245+
max_obj = item;
246+
}
76247
}
77-
} else if (IS_O(o_in, O_COMPLEX)) {
78-
py_obj_base_t *o = o_in;
79-
return py_obj_new_float(machine_sqrt(o->u_complex.real*o->u_complex.real + o->u_complex.imag*o->u_complex.imag));
80-
#endif
248+
if (max_obj == NULL) {
249+
nlr_jump(py_obj_new_exception_2(rt_q_ValueError, "max() arg is an empty sequence", NULL, NULL));
250+
}
251+
return max_obj;
81252
} else {
82-
assert(0);
83-
return py_const_none;
253+
// given many args
254+
py_obj_t max_obj = args[0];
255+
for (int i = 1; i < n_args; i++) {
256+
if (py_obj_less(max_obj, args[i])) {
257+
max_obj = args[i];
258+
}
259+
}
260+
return max_obj;
84261
}
85262
}
86263

87-
py_obj_t py_builtin___build_class__(py_obj_t o_class_fun, py_obj_t o_class_name) {
88-
// we differ from CPython: we set the new __locals__ object here
89-
py_map_t *old_locals = rt_get_map_locals();
90-
py_map_t *class_locals = py_map_new(MAP_QSTR, 0);
91-
rt_set_map_locals(class_locals);
264+
py_obj_t py_builtin_min(int n_args, const py_obj_t *args) {
265+
if (n_args == 1) {
266+
// given an iterable
267+
py_obj_t iterable = rt_getiter(args[0]);
268+
py_obj_t min_obj = NULL;
269+
py_obj_t item;
270+
while ((item = rt_iternext(iterable)) != py_const_stop_iteration) {
271+
if (min_obj == NULL || py_obj_less(item, min_obj)) {
272+
min_obj = item;
273+
}
274+
}
275+
if (min_obj == NULL) {
276+
nlr_jump(py_obj_new_exception_2(rt_q_ValueError, "min() arg is an empty sequence", NULL, NULL));
277+
}
278+
return min_obj;
279+
} else {
280+
// given many args
281+
py_obj_t min_obj = args[0];
282+
for (int i = 1; i < n_args; i++) {
283+
if (py_obj_less(args[i], min_obj)) {
284+
min_obj = args[i];
285+
}
286+
}
287+
return min_obj;
288+
}
289+
}
92290

93-
// call the class code
94-
rt_call_function_1(o_class_fun, (py_obj_t)0xdeadbeef);
291+
py_obj_t py_builtin_ord(py_obj_t o_in) {
292+
const char *str = qstr_str(py_obj_get_qstr(o_in));
293+
if (strlen(str) == 1) {
294+
return py_obj_new_int(str[0]);
295+
} else {
296+
nlr_jump(py_obj_new_exception_2(rt_q_TypeError, "ord() expected a character, but string of length %d found", (void*)(machine_int_t)strlen(str), NULL));
297+
}
298+
}
95299

96-
// restore old __locals__ object
97-
rt_set_map_locals(old_locals);
300+
py_obj_t py_builtin_pow(int n_args, const py_obj_t *args) {
301+
switch (n_args) {
302+
case 2: return rt_binary_op(RT_BINARY_OP_POWER, args[0], args[1]);
303+
case 3: return rt_binary_op(RT_BINARY_OP_MODULO, rt_binary_op(RT_BINARY_OP_POWER, args[0], args[1]), args[2]); // TODO optimise...
304+
default: nlr_jump(py_obj_new_exception_2(rt_q_TypeError, "pow expected at most 3 arguments, got %d", (void*)(machine_int_t)n_args, NULL));
305+
}
306+
}
98307

99-
// create and return the new class
100-
py_obj_base_t *o = m_new(py_obj_base_t, 1);
101-
o->kind = O_CLASS;
102-
o->u_class.locals = class_locals;
103-
return o;
308+
py_obj_t py_builtin_print(int n_args, const py_obj_t *args) {
309+
for (int i = 0; i < n_args; i++) {
310+
if (i > 0) {
311+
printf(" ");
312+
}
313+
if (IS_O(args[i], O_STR)) {
314+
// special case, print string raw
315+
printf("%s", qstr_str(((py_obj_base_t*)args[i])->u_str));
316+
} else {
317+
// print the object Python style
318+
py_obj_print(args[i]);
319+
}
320+
}
321+
printf("\n");
322+
return py_const_none;
104323
}
105324

106-
py_obj_t py_builtin_range(int n_args, const py_obj_t* args) {
325+
py_obj_t py_builtin_range(int n_args, const py_obj_t *args) {
107326
switch (n_args) {
108327
case 1: return py_obj_new_range(0, py_obj_get_int(args[0]), 1);
109328
case 2: return py_obj_new_range(py_obj_get_int(args[0]), py_obj_get_int(args[1]), 1);
110329
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]));
111330
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));
112331
}
113332
}
333+
334+
py_obj_t py_builtin_sum(int n_args, const py_obj_t *args) {
335+
py_obj_t value;
336+
switch (n_args) {
337+
case 1: value = py_obj_new_int(0); break;
338+
case 2: value = args[1]; break;
339+
default: nlr_jump(py_obj_new_exception_2(rt_q_TypeError, "sum expected at most 2 arguments, got %d", (void*)(machine_int_t)n_args, NULL));
340+
}
341+
py_obj_t iterable = rt_getiter(args[0]);
342+
py_obj_t item;
343+
while ((item = rt_iternext(iterable)) != py_const_stop_iteration) {
344+
value = rt_binary_op(RT_BINARY_OP_ADD, value, item);
345+
}
346+
return value;
347+
}

0 commit comments

Comments
 (0)