
Qstr's are now split into a linked-list of qstr pools. This has 2 benefits: the first pool can be in ROM (huge benefit, since we no longer use RAM for the core qstrs), and subsequent pools use m_new for the next pool instead of m_renew (thus avoiding a huge single table for all the qstrs). Still would be better to use a hash table, but this scheme takes us part of the way (eventually convert the pools to hash tables). Also fixed bug with import. Also improved the way the module code is referenced (not magic number 1 anymore).
417 lines
13 KiB
C
417 lines
13 KiB
C
#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 "mpconfig.h"
|
|
#include "mpqstr.h"
|
|
#include "obj.h"
|
|
#include "runtime0.h"
|
|
#include "runtime.h"
|
|
#include "map.h"
|
|
#include "builtin.h"
|
|
|
|
mp_obj_t mp_builtin___build_class__(mp_obj_t o_class_fun, mp_obj_t o_class_name) {
|
|
// we differ from CPython: we set the new __locals__ object here
|
|
mp_map_t *old_locals = rt_locals_get();
|
|
mp_map_t *class_locals = mp_map_new(MP_MAP_QSTR, 0);
|
|
rt_locals_set(class_locals);
|
|
|
|
// call the class code
|
|
rt_call_function_1(o_class_fun, (mp_obj_t)0xdeadbeef);
|
|
|
|
// restore old __locals__ object
|
|
rt_locals_set(old_locals);
|
|
|
|
// create and return the new class
|
|
return mp_obj_new_class(class_locals);
|
|
}
|
|
|
|
mp_obj_t mp_builtin___repl_print__(mp_obj_t o) {
|
|
if (o != mp_const_none) {
|
|
mp_obj_print(o);
|
|
printf("\n");
|
|
}
|
|
return mp_const_none;
|
|
}
|
|
|
|
mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
|
|
if (MP_OBJ_IS_SMALL_INT(o_in)) {
|
|
mp_small_int_t val = MP_OBJ_SMALL_INT_VALUE(o_in);
|
|
if (val < 0) {
|
|
val = -val;
|
|
}
|
|
return MP_OBJ_NEW_SMALL_INT(val);
|
|
#if MICROPY_ENABLE_FLOAT
|
|
} else if (MP_OBJ_IS_TYPE(o_in, &float_type)) {
|
|
mp_float_t value = mp_obj_float_get(o_in);
|
|
// TODO check for NaN etc
|
|
if (value < 0) {
|
|
return mp_obj_new_float(-value);
|
|
} else {
|
|
return o_in;
|
|
}
|
|
} else if (MP_OBJ_IS_TYPE(o_in, &complex_type)) {
|
|
mp_float_t real, imag;
|
|
mp_obj_complex_get(o_in, &real, &imag);
|
|
return mp_obj_new_float(machine_sqrt(real*real + imag*imag));
|
|
#endif
|
|
} else {
|
|
assert(0);
|
|
return mp_const_none;
|
|
}
|
|
}
|
|
|
|
mp_obj_t mp_builtin_all(mp_obj_t o_in) {
|
|
mp_obj_t iterable = rt_getiter(o_in);
|
|
mp_obj_t item;
|
|
while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
|
|
if (!rt_is_true(item)) {
|
|
return mp_const_false;
|
|
}
|
|
}
|
|
return mp_const_true;
|
|
}
|
|
|
|
mp_obj_t mp_builtin_any(mp_obj_t o_in) {
|
|
mp_obj_t iterable = rt_getiter(o_in);
|
|
mp_obj_t item;
|
|
while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
|
|
if (rt_is_true(item)) {
|
|
return mp_const_true;
|
|
}
|
|
}
|
|
return mp_const_false;
|
|
}
|
|
|
|
mp_obj_t mp_builtin_bool(int n_args, const mp_obj_t *args) {
|
|
switch (n_args) {
|
|
case 0: return mp_const_false;
|
|
case 1: if (rt_is_true(args[0])) { return mp_const_true; } else { return mp_const_false; }
|
|
default: nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "bool() takes at most 1 argument (%d given)", (void*)(machine_int_t)n_args));
|
|
}
|
|
}
|
|
|
|
mp_obj_t mp_builtin_callable(mp_obj_t o_in) {
|
|
if (mp_obj_is_callable(o_in)) {
|
|
return mp_const_true;
|
|
} else {
|
|
return mp_const_false;
|
|
}
|
|
}
|
|
|
|
#if MICROPY_ENABLE_FLOAT
|
|
mp_obj_t mp_builtin_complex(int n_args, const mp_obj_t *args) {
|
|
assert(0 <= n_args && n_args <= 2);
|
|
|
|
if (n_args == 0) {
|
|
return mp_obj_new_complex(0, 0);
|
|
} else if (n_args == 1) {
|
|
// TODO allow string as first arg and parse it
|
|
if (MP_OBJ_IS_TYPE(args[0], &complex_type)) {
|
|
return args[0];
|
|
} else {
|
|
return mp_obj_new_complex(mp_obj_get_float(args[0]), 0);
|
|
}
|
|
} else {
|
|
mp_float_t real, imag;
|
|
if (MP_OBJ_IS_TYPE(args[0], &complex_type)) {
|
|
mp_obj_get_complex(args[0], &real, &imag);
|
|
} else {
|
|
real = mp_obj_get_float(args[0]);
|
|
imag = 0;
|
|
}
|
|
if (MP_OBJ_IS_TYPE(args[1], &complex_type)) {
|
|
mp_float_t real2, imag2;
|
|
mp_obj_get_complex(args[1], &real2, &imag2);
|
|
real -= imag2;
|
|
imag += real2;
|
|
} else {
|
|
imag += mp_obj_get_float(args[1]);
|
|
}
|
|
return mp_obj_new_complex(real, imag);
|
|
}
|
|
}
|
|
|
|
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_complex_obj, 0, 2, mp_builtin_complex);
|
|
#endif
|
|
|
|
mp_obj_t mp_builtin_chr(mp_obj_t o_in) {
|
|
int ord = mp_obj_get_int(o_in);
|
|
if (0 <= ord && ord <= 0x10ffff) {
|
|
char *str = m_new(char, 2);
|
|
str[0] = ord;
|
|
str[1] = '\0';
|
|
return mp_obj_new_str(qstr_from_str_take(str, 2));
|
|
} else {
|
|
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_ValueError, "chr() arg not in range(0x110000)"));
|
|
}
|
|
}
|
|
|
|
mp_obj_t mp_builtin_dict(void) {
|
|
// TODO create from an iterable!
|
|
return rt_build_map(0);
|
|
}
|
|
|
|
mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) {
|
|
if (MP_OBJ_IS_SMALL_INT(o1_in) && MP_OBJ_IS_SMALL_INT(o2_in)) {
|
|
mp_small_int_t i1 = MP_OBJ_SMALL_INT_VALUE(o1_in);
|
|
mp_small_int_t i2 = MP_OBJ_SMALL_INT_VALUE(o2_in);
|
|
mp_obj_t revs_args[2];
|
|
revs_args[1] = MP_OBJ_NEW_SMALL_INT(i1 / i2);
|
|
revs_args[0] = MP_OBJ_NEW_SMALL_INT(i1 % i2);
|
|
return rt_build_tuple(2, revs_args);
|
|
} else {
|
|
nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError, "unsupported operand type(s) for divmod(): '%s' and '%s'", mp_obj_get_type_str(o1_in), mp_obj_get_type_str(o2_in)));
|
|
}
|
|
}
|
|
|
|
#if MICROPY_ENABLE_FLOAT
|
|
static mp_obj_t mp_builtin_float(int n_args, const mp_obj_t *args) {
|
|
assert(0 <= n_args && n_args <= 1);
|
|
|
|
if (n_args == 0) {
|
|
return mp_obj_new_float(0);
|
|
} else {
|
|
// TODO allow string as arg and parse it
|
|
if (MP_OBJ_IS_TYPE(args[0], &float_type)) {
|
|
return args[0];
|
|
} else {
|
|
return mp_obj_new_float(mp_obj_get_float(args[0]));
|
|
}
|
|
}
|
|
}
|
|
|
|
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_float_obj, 0, 1, mp_builtin_float);
|
|
#endif
|
|
|
|
static mp_obj_t mp_builtin_hash(mp_obj_t o_in) {
|
|
// TODO hash will generally overflow small integer; can we safely truncate it?
|
|
return mp_obj_new_int(mp_obj_hash(o_in));
|
|
}
|
|
|
|
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_hash_obj, mp_builtin_hash);
|
|
|
|
static mp_obj_t mp_builtin_int(int n_args, const mp_obj_t *args) {
|
|
assert(0 <= n_args && n_args <= 2);
|
|
|
|
if (n_args == 0) {
|
|
return MP_OBJ_NEW_SMALL_INT(0);
|
|
} else if (n_args == 1) {
|
|
// TODO if arg is a string then parse it
|
|
return mp_obj_new_int(mp_obj_get_int(args[0]));
|
|
} else { // n_args == 2
|
|
// TODO, parse with given base
|
|
assert(0);
|
|
return MP_OBJ_NEW_SMALL_INT(0);
|
|
}
|
|
}
|
|
|
|
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_int_obj, 0, 2, mp_builtin_int);
|
|
|
|
static mp_obj_t mp_builtin_iter(mp_obj_t o_in) {
|
|
return rt_getiter(o_in);
|
|
}
|
|
|
|
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_iter_obj, mp_builtin_iter);
|
|
|
|
mp_obj_t mp_builtin_len(mp_obj_t o_in) {
|
|
mp_small_int_t len = 0;
|
|
if (MP_OBJ_IS_TYPE(o_in, &str_type)) {
|
|
len = strlen(qstr_str(mp_obj_str_get(o_in)));
|
|
} else if (MP_OBJ_IS_TYPE(o_in, &tuple_type)) {
|
|
uint seq_len;
|
|
mp_obj_t *seq_items;
|
|
mp_obj_tuple_get(o_in, &seq_len, &seq_items);
|
|
len = seq_len;
|
|
} else if (MP_OBJ_IS_TYPE(o_in, &list_type)) {
|
|
uint seq_len;
|
|
mp_obj_t *seq_items;
|
|
mp_obj_list_get(o_in, &seq_len, &seq_items);
|
|
len = seq_len;
|
|
} else if (MP_OBJ_IS_TYPE(o_in, &dict_type)) {
|
|
len = mp_obj_dict_len(o_in);
|
|
} else {
|
|
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "object of type '%s' has no len()", mp_obj_get_type_str(o_in)));
|
|
}
|
|
return MP_OBJ_NEW_SMALL_INT(len);
|
|
}
|
|
|
|
mp_obj_t mp_builtin_list(int n_args, const mp_obj_t *args) {
|
|
switch (n_args) {
|
|
case 0: return rt_build_list(0, NULL);
|
|
case 1:
|
|
{
|
|
// make list from iterable
|
|
mp_obj_t iterable = rt_getiter(args[0]);
|
|
mp_obj_t list = rt_build_list(0, NULL);
|
|
mp_obj_t item;
|
|
while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
|
|
rt_list_append(list, item);
|
|
}
|
|
return list;
|
|
}
|
|
default: nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "list() takes at most 1 argument (%d given)", (void*)(machine_int_t)n_args));
|
|
}
|
|
}
|
|
|
|
mp_obj_t mp_builtin_max(int n_args, const mp_obj_t *args) {
|
|
if (n_args == 1) {
|
|
// given an iterable
|
|
mp_obj_t iterable = rt_getiter(args[0]);
|
|
mp_obj_t max_obj = NULL;
|
|
mp_obj_t item;
|
|
while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
|
|
if (max_obj == NULL || mp_obj_less(max_obj, item)) {
|
|
max_obj = item;
|
|
}
|
|
}
|
|
if (max_obj == NULL) {
|
|
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_ValueError, "max() arg is an empty sequence"));
|
|
}
|
|
return max_obj;
|
|
} else {
|
|
// given many args
|
|
mp_obj_t max_obj = args[0];
|
|
for (int i = 1; i < n_args; i++) {
|
|
if (mp_obj_less(max_obj, args[i])) {
|
|
max_obj = args[i];
|
|
}
|
|
}
|
|
return max_obj;
|
|
}
|
|
}
|
|
|
|
mp_obj_t mp_builtin_min(int n_args, const mp_obj_t *args) {
|
|
if (n_args == 1) {
|
|
// given an iterable
|
|
mp_obj_t iterable = rt_getiter(args[0]);
|
|
mp_obj_t min_obj = NULL;
|
|
mp_obj_t item;
|
|
while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
|
|
if (min_obj == NULL || mp_obj_less(item, min_obj)) {
|
|
min_obj = item;
|
|
}
|
|
}
|
|
if (min_obj == NULL) {
|
|
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_ValueError, "min() arg is an empty sequence"));
|
|
}
|
|
return min_obj;
|
|
} else {
|
|
// given many args
|
|
mp_obj_t min_obj = args[0];
|
|
for (int i = 1; i < n_args; i++) {
|
|
if (mp_obj_less(args[i], min_obj)) {
|
|
min_obj = args[i];
|
|
}
|
|
}
|
|
return min_obj;
|
|
}
|
|
}
|
|
|
|
static mp_obj_t mp_builtin_next(mp_obj_t o) {
|
|
mp_obj_t ret = rt_iternext(o);
|
|
if (ret == mp_const_stop_iteration) {
|
|
nlr_jump(mp_obj_new_exception(MP_QSTR_StopIteration));
|
|
} else {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_next_obj, mp_builtin_next);
|
|
|
|
mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
|
|
const char *str = qstr_str(mp_obj_get_qstr(o_in));
|
|
if (strlen(str) == 1) {
|
|
return mp_obj_new_int(str[0]);
|
|
} else {
|
|
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "ord() expected a character, but string of length %d found", (void*)(machine_int_t)strlen(str)));
|
|
}
|
|
}
|
|
|
|
mp_obj_t mp_builtin_pow(int n_args, const mp_obj_t *args) {
|
|
switch (n_args) {
|
|
case 2: return rt_binary_op(RT_BINARY_OP_POWER, args[0], args[1]);
|
|
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...
|
|
default: nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "pow expected at most 3 arguments, got %d", (void*)(machine_int_t)n_args));
|
|
}
|
|
}
|
|
|
|
mp_obj_t mp_builtin_print(int n_args, const mp_obj_t *args) {
|
|
for (int i = 0; i < n_args; i++) {
|
|
if (i > 0) {
|
|
printf(" ");
|
|
}
|
|
if (MP_OBJ_IS_TYPE(args[i], &str_type)) {
|
|
// special case, print string raw
|
|
printf("%s", qstr_str(mp_obj_str_get(args[i])));
|
|
} else {
|
|
// print the object Python style
|
|
mp_obj_print(args[i]);
|
|
}
|
|
}
|
|
printf("\n");
|
|
return mp_const_none;
|
|
}
|
|
|
|
mp_obj_t mp_builtin_range(int n_args, const mp_obj_t *args) {
|
|
switch (n_args) {
|
|
case 1: return mp_obj_new_range(0, mp_obj_get_int(args[0]), 1);
|
|
case 2: return mp_obj_new_range(mp_obj_get_int(args[0]), mp_obj_get_int(args[1]), 1);
|
|
case 3: return mp_obj_new_range(mp_obj_get_int(args[0]), mp_obj_get_int(args[1]), mp_obj_get_int(args[2]));
|
|
default: nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "range expected at most 3 arguments, got %d", (void*)(machine_int_t)n_args));
|
|
}
|
|
}
|
|
|
|
static mp_obj_t mp_builtin_set(int n_args, const mp_obj_t *args) {
|
|
assert(0 <= n_args && n_args <= 1);
|
|
|
|
if (n_args == 0) {
|
|
// return a new, empty set
|
|
return mp_obj_new_set(0, NULL);
|
|
} else {
|
|
// 1 argument, an iterable from which we make a new set
|
|
mp_obj_t set = mp_obj_new_set(0, NULL);
|
|
mp_obj_t iterable = rt_getiter(args[0]);
|
|
mp_obj_t item;
|
|
while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
|
|
mp_obj_set_store(set, item);
|
|
}
|
|
return set;
|
|
}
|
|
}
|
|
|
|
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_set_obj, 0, 1, mp_builtin_set);
|
|
|
|
mp_obj_t mp_builtin_sum(int n_args, const mp_obj_t *args) {
|
|
mp_obj_t value;
|
|
switch (n_args) {
|
|
case 1: value = mp_obj_new_int(0); break;
|
|
case 2: value = args[1]; break;
|
|
default: nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "sum expected at most 2 arguments, got %d", (void*)(machine_int_t)n_args));
|
|
}
|
|
mp_obj_t iterable = rt_getiter(args[0]);
|
|
mp_obj_t item;
|
|
while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
|
|
value = rt_binary_op(RT_BINARY_OP_ADD, value, item);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
static mp_obj_t mp_builtin_type(mp_obj_t o_in) {
|
|
// TODO implement the 3 argument version of type()
|
|
if (MP_OBJ_IS_SMALL_INT(o_in)) {
|
|
// TODO implement int-type
|
|
return mp_const_none;
|
|
} else {
|
|
mp_obj_base_t *o = o_in;
|
|
return (mp_obj_t)o->type;
|
|
}
|
|
}
|
|
|
|
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_type_obj, mp_builtin_type);
|