STATIC mp_obj_t btree_init_iter(size_t n_args, const mp_obj_t *args, byte type) { mp_obj_btree_t *self = MP_OBJ_TO_PTR(args[0]); self->next_flags = type; self->start_key = mp_const_none; self->end_key = mp_const_none; if (n_args > 1) { self->start_key = args[1]; if (n_args > 2) { self->end_key = args[2]; if (n_args > 3) { self->next_flags = type | MP_OBJ_SMALL_INT_VALUE(args[3]); } } } return args[0]; }
mp_obj_t mp_obj_tuple_unary_op(mp_uint_t op, mp_obj_t self_in) { mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(self->len != 0); case MP_UNARY_OP_HASH: { // start hash with pointer to empty tuple, to make it fairly unique mp_int_t hash = (mp_int_t)mp_const_empty_tuple; for (size_t i = 0; i < self->len; i++) { hash += MP_OBJ_SMALL_INT_VALUE(mp_unary_op(MP_UNARY_OP_HASH, self->items[i])); } return MP_OBJ_NEW_SMALL_INT(hash); } case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->len); default: return MP_OBJ_NULL; // op not supported } }
STATIC mp_obj_t mod_socket_getaddrinfo(uint n_args, const mp_obj_t *args) { // TODO: Implement all args assert(n_args == 2); assert(MP_OBJ_IS_STR(args[0])); const char *host = mp_obj_str_get_str(args[0]); const char *serv = NULL; // getaddrinfo accepts port in string notation, so however // it may seem stupid, we need to convert int to str if (MP_OBJ_IS_SMALL_INT(args[1])) { int port = (short)MP_OBJ_SMALL_INT_VALUE(args[1]); char buf[6]; sprintf(buf, "%d", port); serv = buf; } else { serv = mp_obj_str_get_str(args[1]); } struct addrinfo hints; struct addrinfo *addr; memset(&hints, 0, sizeof(hints)); int res = getaddrinfo(host, serv, NULL/*&hints*/, &addr); if (res != 0) { // CPython: socket.gaierror nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[addrinfo error %d]", res)); } assert(addr); mp_obj_t list = mp_obj_new_list(0, NULL); for (; addr; addr = addr->ai_next) { mp_obj_tuple_t *t = mp_obj_new_tuple(5, NULL); t->items[0] = MP_OBJ_NEW_SMALL_INT((machine_int_t)addr->ai_family); t->items[1] = MP_OBJ_NEW_SMALL_INT((machine_int_t)addr->ai_socktype); t->items[2] = MP_OBJ_NEW_SMALL_INT((machine_int_t)addr->ai_protocol); // "canonname will be a string representing the canonical name of the host // if AI_CANONNAME is part of the flags argument; else canonname will be empty." ?? if (addr->ai_canonname) { t->items[3] = MP_OBJ_NEW_QSTR(qstr_from_str(addr->ai_canonname)); } else { t->items[3] = mp_const_none; } t->items[4] = mp_obj_new_bytearray(addr->ai_addrlen, addr->ai_addr); mp_obj_list_append(list, t); } return list; }
// Unbuffered, inefficient implementation of readline() for raw I/O files. STATIC mp_obj_t stream_unbuffered_readline(uint n_args, const mp_obj_t *args) { struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)args[0]; if (o->type->stream_p == NULL || o->type->stream_p->read == NULL) { // CPython: io.UnsupportedOperation, OSError subclass nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Operation not supported")); } mp_int_t max_size = -1; if (n_args > 1) { max_size = MP_OBJ_SMALL_INT_VALUE(args[1]); } vstr_t *vstr; if (max_size != -1) { vstr = vstr_new_size(max_size); } else { vstr = vstr_new(); } int error; while (max_size == -1 || max_size-- != 0) { char *p = vstr_add_len(vstr, 1); if (p == NULL) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError, "out of memory")); } mp_int_t out_sz = o->type->stream_p->read(o, p, 1, &error); if (out_sz == -1) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error)); } if (out_sz == 0) { // Back out previously added byte // TODO: This is a bit hacky, does it supported by vstr API contract? // Consider, what's better - read a char and get OutOfMemory (so read // char is lost), or allocate first as we do. vstr_add_len(vstr, -1); break; } if (*p == '\n') { break; } } // TODO need a string creation API that doesn't copy the given data mp_obj_t ret = mp_obj_new_str_of_type(STREAM_CONTENT_TYPE(o->type->stream_p), (byte*)vstr->buf, vstr->len); vstr_free(vstr); return ret; }
// convert a Micro Python object to a sensible value for inline asm STATIC machine_uint_t convert_obj_for_inline_asm(mp_obj_t obj) { // TODO for byte_array, pass pointer to the array if (MP_OBJ_IS_SMALL_INT(obj)) { return MP_OBJ_SMALL_INT_VALUE(obj); } else if (obj == mp_const_none) { return 0; } else if (obj == mp_const_false) { return 0; } else if (obj == mp_const_true) { return 1; } else if (MP_OBJ_IS_STR(obj)) { // pointer to the string (it's probably constant though!) uint l; return (machine_uint_t)mp_obj_str_get_data(obj, &l); } else { mp_obj_type_t *type = mp_obj_get_type(obj); if (0) { #if MICROPY_PY_BUILTINS_FLOAT } else if (type == &mp_type_float) { // convert float to int (could also pass in float registers) return (machine_int_t)mp_obj_float_get(obj); #endif } else if (type == &mp_type_tuple) { // pointer to start of tuple (could pass length, but then could use len(x) for that) uint len; mp_obj_t *items; mp_obj_tuple_get(obj, &len, &items); return (machine_uint_t)items; } else if (type == &mp_type_list) { // pointer to start of list (could pass length, but then could use len(x) for that) uint len; mp_obj_t *items; mp_obj_list_get(obj, &len, &items); return (machine_uint_t)items; } else { mp_buffer_info_t bufinfo; if (mp_get_buffer(obj, &bufinfo, MP_BUFFER_WRITE)) { // supports the buffer protocol, return a pointer to the data return (machine_uint_t)bufinfo.buf; } else { // just pass along a pointer to the object return (machine_uint_t)obj; } } } }
STATIC mp_obj_t bytearray_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 0, 1, false); if (n_args == 0) { // no args: construct an empty bytearray return array_new(BYTEARRAY_TYPECODE, 0); } else if (MP_OBJ_IS_SMALL_INT(args[0])) { // 1 arg, an integer: construct a blank bytearray of that length uint len = MP_OBJ_SMALL_INT_VALUE(args[0]); mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, len); memset(o->items, 0, len); return o; } else { // 1 arg, an iterator: construct the bytearray from that return array_construct(BYTEARRAY_TYPECODE, args[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 mp_obj_equal(mp_obj_t o1, mp_obj_t o2) { if (o1 == o2) { return true; } else if (o1 == mp_const_none || o2 == mp_const_none) { return false; } else if (MP_OBJ_IS_SMALL_INT(o1) || MP_OBJ_IS_SMALL_INT(o2)) { if (MP_OBJ_IS_SMALL_INT(o1) && MP_OBJ_IS_SMALL_INT(o2)) { return false; } else { if (MP_OBJ_IS_SMALL_INT(o2)) { mp_obj_t temp = o1; o1 = o2; o2 = temp; } // o1 is the SMALL_INT, o2 is not mp_small_int_t val = MP_OBJ_SMALL_INT_VALUE(o1); if (o2 == mp_const_false) { return val == 0; } else if (o2 == mp_const_true) { return val == 1; } else if (MP_OBJ_IS_TYPE(o2, &mp_type_int)) { // If o2 is long int, dispatch to its virtual methods mp_obj_base_t *o = o2; if (o->type->binary_op != NULL) { mp_obj_t r = o->type->binary_op(MP_BINARY_OP_EQUAL, o2, o1); return r == mp_const_true ? true : false; } } return false; } } else if (MP_OBJ_IS_STR(o1) && MP_OBJ_IS_STR(o2)) { return mp_obj_str_equal(o1, o2); } else { mp_obj_base_t *o = o1; if (o->type->binary_op != NULL) { mp_obj_t r = o->type->binary_op(MP_BINARY_OP_EQUAL, o1, o2); if (r != MP_OBJ_NULL) { return r == mp_const_true ? true : false; } } nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_NotImplementedError, "Equality for '%s' and '%s' types not yet implemented", mp_obj_get_type_str(o1), mp_obj_get_type_str(o2))); return false; } }
STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) { // bytearrays can be raw-initialised from anything with the buffer protocol // other arrays can only be raw-initialised from bytes and bytearray objects mp_buffer_info_t bufinfo; if (((MICROPY_PY_BUILTINS_BYTEARRAY && typecode == BYTEARRAY_TYPECODE) || (MICROPY_PY_ARRAY && (MP_OBJ_IS_TYPE(initializer, &mp_type_bytes) || (MICROPY_PY_BUILTINS_BYTEARRAY && MP_OBJ_IS_TYPE(initializer, &mp_type_bytearray))))) && mp_get_buffer(initializer, &bufinfo, MP_BUFFER_READ)) { // construct array from raw bytes // we round-down the len to make it a multiple of sz (CPython raises error) size_t sz = mp_binary_get_size('@', typecode, NULL); mp_uint_t len = bufinfo.len / sz; mp_obj_array_t *o = array_new(typecode, len); memcpy(o->items, bufinfo.buf, len * sz); return o; } mp_uint_t len; // Try to create array of exact len if initializer len is known mp_obj_t len_in = mp_obj_len_maybe(initializer); if (len_in == MP_OBJ_NULL) { len = 0; } else { len = MP_OBJ_SMALL_INT_VALUE(len_in); } mp_obj_array_t *array = array_new(typecode, len); mp_obj_t iterable = mp_getiter(initializer); mp_obj_t item; mp_uint_t i = 0; while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { if (len == 0) { array_append(array, item); } else { mp_binary_set_val_array(typecode, array->items, i++, item); } } return array; }
STATIC mp_obj_t socket_sendto(size_t n_args, const mp_obj_t *args) { mp_obj_socket_t *self = MP_OBJ_TO_PTR(args[0]); int flags = 0; mp_obj_t dst_addr = args[2]; if (n_args > 3) { flags = MP_OBJ_SMALL_INT_VALUE(args[2]); dst_addr = args[3]; } mp_buffer_info_t bufinfo, addr_bi; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); mp_get_buffer_raise(dst_addr, &addr_bi, MP_BUFFER_READ); int out_sz = sendto(self->fd, bufinfo.buf, bufinfo.len, flags, (struct sockaddr *)addr_bi.buf, addr_bi.len); RAISE_ERRNO(out_sz, errno); return MP_OBJ_NEW_SMALL_INT(out_sz); }
int rt_is_true(mp_obj_t arg) { DEBUG_OP_printf("is true %p\n", arg); if (MP_OBJ_IS_SMALL_INT(arg)) { if (MP_OBJ_SMALL_INT_VALUE(arg) == 0) { return 0; } else { return 1; } } else if (arg == mp_const_none) { return 0; } else if (arg == mp_const_false) { return 0; } else if (arg == mp_const_true) { return 1; } else { assert(0); return 0; } }
STATIC mp_obj_t fdfile_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { mp_obj_fdfile_t *o = m_new_obj(mp_obj_fdfile_t); o->base.type = type_in; if (MP_OBJ_IS_SMALL_INT(args[0])) { o->fd = MP_OBJ_SMALL_INT_VALUE(args[0]); return o; } const char *fname = mp_obj_str_get_str(args[0]); const char *mode_s; if (n_args > 1) { mode_s = mp_obj_str_get_str(args[1]); } else { mode_s = "r"; } int mode = 0; while (*mode_s) { switch (*mode_s++) { // Note: these assume O_RDWR = O_RDONLY | O_WRONLY case 'r': mode |= O_RDONLY; break; case 'w': mode |= O_WRONLY | O_CREAT | O_TRUNC; break; case 'a': mode |= O_APPEND; break; case '+': mode |= O_RDWR; break; } } int fd = open(fname, mode, 0644); if (fd == -1) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", errno)); } return fdfile_new(fd); }
STATIC mp_obj_t it_iternext(mp_obj_t self_in) { mp_obj_getitem_iter_t *self = self_in; nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { // try to get next item mp_obj_t value = rt_call_method_n_kw(1, 0, self->args); self->args[2] = MP_OBJ_NEW_SMALL_INT(MP_OBJ_SMALL_INT_VALUE(self->args[2]) + 1); nlr_pop(); return value; } else { // an exception was raised if (mp_obj_get_type(nlr.ret_val) == &mp_type_StopIteration) { // return mp_const_stop_iteration instead of raising StopIteration return mp_const_stop_iteration; } else { // re-raise exception nlr_jump(nlr.ret_val); } } }
mp_float_t mp_obj_get_float(mp_obj_t arg) { if (arg == mp_const_false) { return 0; } else if (arg == mp_const_true) { return 1; } else if (MP_OBJ_IS_SMALL_INT(arg)) { return MP_OBJ_SMALL_INT_VALUE(arg); } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { return mp_obj_int_as_float(arg); } else if (mp_obj_is_float(arg)) { return mp_obj_float_get(arg); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "can't convert to float")); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to float", mp_obj_get_type_str(arg))); } } }
STATIC mp_obj_t socket_setsockopt(uint n_args, const mp_obj_t *args) { mp_obj_socket_t *self = args[0]; int level = MP_OBJ_SMALL_INT_VALUE(args[1]); int option = mp_obj_get_int(args[2]); const void *optval; socklen_t optlen; if (MP_OBJ_IS_INT(args[3])) { int val = mp_obj_int_get(args[3]); optval = &val; optlen = sizeof(val); } else { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); optval = bufinfo.buf; optlen = bufinfo.len; } int r = setsockopt(self->fd, level, option, optval, optlen); RAISE_ERRNO(r, errno); return mp_const_none; }
mp_int_t mp_obj_get_int(mp_const_obj_t arg) { // This function essentially performs implicit type conversion to int // Note that Python does NOT provide implicit type conversion from // float to int in the core expression language, try some_list[1.0]. if (arg == mp_const_false) { return 0; } else if (arg == mp_const_true) { return 1; } else if (MP_OBJ_IS_SMALL_INT(arg)) { return MP_OBJ_SMALL_INT_VALUE(arg); } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { return mp_obj_int_get_checked(arg); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("can't convert to int"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to int", mp_obj_get_type_str(arg))); } } }
mp_int_t mp_obj_hash(mp_obj_t o_in) { if (o_in == mp_const_false) { return 0; // needs to hash to same as the integer 0, since False==0 } else if (o_in == mp_const_true) { return 1; // needs to hash to same as the integer 1, since True==1 } else if (MP_OBJ_IS_SMALL_INT(o_in)) { return MP_OBJ_SMALL_INT_VALUE(o_in); } else if (MP_OBJ_IS_TYPE(o_in, &mp_type_int)) { return mp_obj_int_hash(o_in); } else if (MP_OBJ_IS_STR(o_in) || MP_OBJ_IS_TYPE(o_in, &mp_type_bytes)) { return mp_obj_str_get_hash(o_in); } else if (MP_OBJ_IS_TYPE(o_in, &mp_type_NoneType)) { return (mp_int_t)o_in; } else if (MP_OBJ_IS_FUN(o_in)) { return (mp_int_t)o_in; } else if (MP_OBJ_IS_TYPE(o_in, &mp_type_tuple)) { return mp_obj_tuple_hash(o_in); } else if (MP_OBJ_IS_TYPE(o_in, &mp_type_type)) { return (mp_int_t)o_in; } else if (MP_OBJ_IS_OBJ(o_in)) { // if a valid __hash__ method exists, use it mp_obj_t hash_method[2]; mp_load_method_maybe(o_in, MP_QSTR___hash__, hash_method); if (hash_method[0] != MP_OBJ_NULL) { mp_obj_t hash_val = mp_call_method_n_kw(0, 0, hash_method); if (MP_OBJ_IS_INT(hash_val)) { return mp_obj_int_get_truncated(hash_val); } } } // TODO hash class and instances - in CPython by default user created classes' __hash__ resolves to their id if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "unhashable type")); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unhashable type: '%s'", mp_obj_get_type_str(o_in))); } }
bool mp_obj_get_float_maybe(mp_obj_t arg, mp_float_t *value) { mp_float_t val; if (arg == mp_const_false) { val = 0; } else if (arg == mp_const_true) { val = 1; } else if (MP_OBJ_IS_SMALL_INT(arg)) { val = MP_OBJ_SMALL_INT_VALUE(arg); #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { val = mp_obj_int_as_float_impl(arg); #endif } else if (mp_obj_is_float(arg)) { val = mp_obj_float_get(arg); } else { return false; } *value = val; return true; }
void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { if (arg == mp_const_false) { *real = 0; *imag = 0; } else if (arg == mp_const_true) { *real = 1; *imag = 0; } else if (MP_OBJ_IS_SMALL_INT(arg)) { *real = MP_OBJ_SMALL_INT_VALUE(arg); *imag = 0; } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { *real = mp_obj_int_as_float(arg); *imag = 0; } else if (MP_OBJ_IS_TYPE(arg, &mp_type_float)) { *real = mp_obj_float_get(arg); *imag = 0; } else if (MP_OBJ_IS_TYPE(arg, &mp_type_complex)) { mp_obj_complex_get(arg, real, imag); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to complex", mp_obj_get_type_str(arg))); } }
STATIC mp_obj_t btree_seq(size_t n_args, const mp_obj_t *args) { mp_obj_btree_t *self = MP_OBJ_TO_PTR(args[0]); int flags = MP_OBJ_SMALL_INT_VALUE(args[1]); DBT key, val; if (n_args > 2) { // Different ports may have different type sizes mp_uint_t v; key.data = (void*)mp_obj_str_get_data(args[2], &v); key.size = v; } int res = __bt_seq(self->db, &key, &val, flags); if (res == RET_SPECIAL) { return mp_const_none; } mp_obj_t pair_o = mp_obj_new_tuple(2, NULL); mp_obj_tuple_t *pair = MP_OBJ_TO_PTR(pair_o); pair->items[0] = mp_obj_new_bytes(key.data, key.size); pair->items[1] = mp_obj_new_bytes(val.data, val.size); return pair_o; }
static mp_obj_t str_split(uint n_args, const mp_obj_t *args) { int splits = -1; mp_obj_t sep = mp_const_none; if (n_args > 1) { sep = args[1]; if (n_args > 2) { splits = MP_OBJ_SMALL_INT_VALUE(args[2]); } } assert(sep == mp_const_none); (void)sep; // unused; to hush compiler warning mp_obj_t res = mp_obj_new_list(0, NULL); GET_STR_DATA_LEN(args[0], s, len); const byte *top = s + len; const byte *start; // Initial whitespace is not counted as split, so we pre-do it while (s < top && is_ws(*s)) s++; while (s < top && splits != 0) { start = s; while (s < top && !is_ws(*s)) s++; rt_list_append(res, mp_obj_new_str(start, s - start, false)); if (s >= top) { break; } while (s < top && is_ws(*s)) s++; if (splits > 0) { splits--; } } if (s < top) { rt_list_append(res, mp_obj_new_str(s, top - s, false)); } return res; }
// is_slice determines whether the index is a slice index size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool is_slice) { mp_int_t i; if (MP_OBJ_IS_SMALL_INT(index)) { i = MP_OBJ_SMALL_INT_VALUE(index); } else if (!mp_obj_get_int_maybe(index, &i)) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("indices must be integers"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%q indices must be integers, not %s", type->name, mp_obj_get_type_str(index))); } } if (i < 0) { i += len; } if (is_slice) { if (i < 0) { i = 0; } else if ((mp_uint_t)i > len) { i = len; } } else { if (i < 0 || (mp_uint_t)i >= len) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_msg(&mp_type_IndexError, "index out of range"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "%q index out of range", type->name)); } } } // By this point 0 <= i <= len and so fits in a size_t return (size_t)i; }
// is_slice determines whether the index is a slice index mp_uint_t mp_get_index(const mp_obj_type_t *type, mp_uint_t len, mp_obj_t index, bool is_slice) { mp_int_t i; if (MP_OBJ_IS_SMALL_INT(index)) { i = MP_OBJ_SMALL_INT_VALUE(index); } else if (!mp_obj_get_int_maybe(index, &i)) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "indices must be integers")); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%s indices must be integers, not %s", qstr_str(type->name), mp_obj_get_type_str(index))); } } if (i < 0) { i += len; } if (is_slice) { if (i < 0) { i = 0; } else if (i > len) { i = len; } } else { if (i < 0 || i >= len) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "index out of range")); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "%s index out of range", qstr_str(type->name))); } } } return i; }
STATIC mp_obj_t struct_pack(uint n_args, mp_obj_t *args) { // TODO: "The arguments must match the values required by the format exactly." const char *fmt = mp_obj_str_get_str(args[0]); char fmt_type = get_fmt_type(&fmt); int size = MP_OBJ_SMALL_INT_VALUE(struct_calcsize(args[0])); byte *p; mp_obj_t res = mp_obj_str_builder_start(&mp_type_bytes, size, &p); memset(p, 0, size); for (uint i = 1; i < n_args; i++) { machine_uint_t sz = 1; if (unichar_isdigit(*fmt)) { sz = get_fmt_num(&fmt); } if (sz > 1) { // TODO: size spec support only for string len assert(*fmt == 's'); } if (*fmt == 's') { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[i], &bufinfo, MP_BUFFER_READ); machine_uint_t to_copy = sz; if (bufinfo.len < to_copy) { to_copy = bufinfo.len; } memcpy(p, bufinfo.buf, to_copy); memset(p + to_copy, 0, sz - to_copy); p += sz; fmt++; } else { mp_binary_set_val(fmt_type, *fmt++, args[i], &p); } } return res; }
STATIC mp_obj_t list_insert(mp_obj_t self_in, mp_obj_t idx, mp_obj_t obj) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); mp_obj_list_t *self = self_in; // insert has its own strange index logic int index = MP_OBJ_SMALL_INT_VALUE(idx); if (index < 0) { index += self->len; } if (index < 0) { index = 0; } if (index > self->len) { index = self->len; } mp_obj_list_append(self_in, mp_const_none); for (int i = self->len-1; i > index; i--) { self->items[i] = self->items[i-1]; } self->items[index] = obj; return mp_const_none; }
// convert a Micro Python object to a sensible value for inline asm STATIC machine_uint_t convert_obj_for_inline_asm(mp_obj_t obj) { // TODO for byte_array, pass pointer to the array if (MP_OBJ_IS_SMALL_INT(obj)) { return MP_OBJ_SMALL_INT_VALUE(obj); } else if (obj == mp_const_none) { return 0; } else if (obj == mp_const_false) { return 0; } else if (obj == mp_const_true) { return 1; } else if (MP_OBJ_IS_STR(obj)) { // pointer to the string (it's probably constant though!) uint l; return (machine_uint_t)mp_obj_str_get_data(obj, &l); #if MICROPY_ENABLE_FLOAT } else if (MP_OBJ_IS_TYPE(obj, &mp_type_float)) { // convert float to int (could also pass in float registers) return (machine_int_t)mp_obj_float_get(obj); #endif } else if (MP_OBJ_IS_TYPE(obj, &mp_type_tuple)) { // pointer to start of tuple (could pass length, but then could use len(x) for that) uint len; mp_obj_t *items; mp_obj_tuple_get(obj, &len, &items); return (machine_uint_t)items; } else if (MP_OBJ_IS_TYPE(obj, &mp_type_list)) { // pointer to start of list (could pass length, but then could use len(x) for that) uint len; mp_obj_t *items; mp_obj_list_get(obj, &len, &items); return (machine_uint_t)items; } else { // just pass along a pointer to the object return (machine_uint_t)obj; } }
STATIC mp_obj_t set_unary_op(mp_unary_op_t op, mp_obj_t self_in) { mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(self->set.used != 0); case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->set.used); #if MICROPY_PY_BUILTINS_FROZENSET case MP_UNARY_OP_HASH: if (MP_OBJ_IS_TYPE(self_in, &mp_type_frozenset)) { // start hash with unique value mp_int_t hash = (mp_int_t)(uintptr_t)&mp_type_frozenset; size_t max = self->set.alloc; mp_set_t *set = &self->set; for (size_t i = 0; i < max; i++) { if (MP_SET_SLOT_IS_FILLED(set, i)) { hash += MP_OBJ_SMALL_INT_VALUE(mp_unary_op(MP_UNARY_OP_HASH, set->table[i])); } } return MP_OBJ_NEW_SMALL_INT(hash); } #endif default: return MP_OBJ_NULL; // op not supported } }
STATIC mp_obj_t mod_socket_getaddrinfo(size_t n_args, const mp_obj_t *args) { // TODO: Implement 5th and 6th args const char *host = mp_obj_str_get_str(args[0]); const char *serv = NULL; struct addrinfo hints; char buf[6]; memset(&hints, 0, sizeof(hints)); // getaddrinfo accepts port in string notation, so however // it may seem stupid, we need to convert int to str if (MP_OBJ_IS_SMALL_INT(args[1])) { unsigned port = (unsigned short)MP_OBJ_SMALL_INT_VALUE(args[1]); snprintf(buf, sizeof(buf), "%u", port); serv = buf; hints.ai_flags = AI_NUMERICSERV; #ifdef __UCLIBC_MAJOR__ #if __UCLIBC_MAJOR__ == 0 && (__UCLIBC_MINOR__ < 9 || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ <= 32)) // "warning" requires -Wno-cpp which is a relatively new gcc option, so we choose not to use it. //#warning Working around uClibc bug with numeric service name // Older versions og uClibc have bugs when numeric ports in service // arg require also hints.ai_socktype (or hints.ai_protocol) != 0 // This actually was fixed in 0.9.32.1, but uClibc doesn't allow to // test for that. // http://git.uclibc.org/uClibc/commit/libc/inet/getaddrinfo.c?id=bc3be18145e4d5 // Note that this is crude workaround, precluding UDP socket addresses // to be returned. TODO: set only if not set by Python args. hints.ai_socktype = SOCK_STREAM; #endif #endif } else { serv = mp_obj_str_get_str(args[1]); } if (n_args > 2) { hints.ai_family = MP_OBJ_SMALL_INT_VALUE(args[2]); if (n_args > 3) { hints.ai_socktype = MP_OBJ_SMALL_INT_VALUE(args[3]); } } struct addrinfo *addr_list; int res = getaddrinfo(host, serv, &hints, &addr_list); if (res != 0) { // CPython: socket.gaierror nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[addrinfo error %d]", res)); } assert(addr_list); mp_obj_t list = mp_obj_new_list(0, NULL); for (struct addrinfo *addr = addr_list; addr; addr = addr->ai_next) { mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL)); t->items[0] = MP_OBJ_NEW_SMALL_INT(addr->ai_family); t->items[1] = MP_OBJ_NEW_SMALL_INT(addr->ai_socktype); t->items[2] = MP_OBJ_NEW_SMALL_INT(addr->ai_protocol); // "canonname will be a string representing the canonical name of the host // if AI_CANONNAME is part of the flags argument; else canonname will be empty." ?? if (addr->ai_canonname) { t->items[3] = MP_OBJ_NEW_QSTR(qstr_from_str(addr->ai_canonname)); } else { t->items[3] = mp_const_none; } t->items[4] = mp_obj_new_bytearray(addr->ai_addrlen, addr->ai_addr); mp_obj_list_append(list, MP_OBJ_FROM_PTR(t)); } freeaddrinfo(addr_list); return list; }
STATIC mp_obj_t socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) { mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in); int r = listen(self->fd, MP_OBJ_SMALL_INT_VALUE(backlog_in)); RAISE_ERRNO(r, errno); return mp_const_none; }
mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { GET_STR_DATA_LEN(lhs_in, lhs_data, lhs_len); switch (op) { case RT_BINARY_OP_SUBSCR: // TODO: need predicate to check for int-like type (bools are such for example) // ["no", "yes"][1 == 2] is common idiom if (MP_OBJ_IS_SMALL_INT(rhs_in)) { uint index = mp_get_index(mp_obj_get_type(lhs_in), lhs_len, rhs_in); return mp_obj_new_str(lhs_data + index, 1, true); #if MICROPY_ENABLE_SLICE } else if (MP_OBJ_IS_TYPE(rhs_in, &slice_type)) { machine_int_t start, stop, step; mp_obj_slice_get(rhs_in, &start, &stop, &step); assert(step == 1); if (start < 0) { start = lhs_len + start; if (start < 0) { start = 0; } } else if (start > lhs_len) { start = lhs_len; } if (stop <= 0) { stop = lhs_len + stop; // CPython returns empty string in such case if (stop < 0) { stop = start; } } else if (stop > lhs_len) { stop = lhs_len; } return mp_obj_new_str(lhs_data + start, stop - start, false); #endif } else { // Message doesn't match CPython, but we don't have so much bytes as they // to spend them on verbose wording nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "index must be int")); } case RT_BINARY_OP_ADD: case RT_BINARY_OP_INPLACE_ADD: if (MP_OBJ_IS_STR(rhs_in)) { // add 2 strings GET_STR_DATA_LEN(rhs_in, rhs_data, rhs_len); int alloc_len = lhs_len + rhs_len; /* code for making qstr byte *q_ptr; byte *val = qstr_build_start(alloc_len, &q_ptr); memcpy(val, lhs_data, lhs_len); memcpy(val + lhs_len, rhs_data, rhs_len); return MP_OBJ_NEW_QSTR(qstr_build_end(q_ptr)); */ // code for non-qstr byte *data; mp_obj_t s = mp_obj_str_builder_start(alloc_len, &data); memcpy(data, lhs_data, lhs_len); memcpy(data + lhs_len, rhs_data, rhs_len); return mp_obj_str_builder_end(s); } break; case RT_COMPARE_OP_IN: case RT_COMPARE_OP_NOT_IN: /* NOTE `a in b` is `b.__contains__(a)` */ if (MP_OBJ_IS_STR(rhs_in)) { GET_STR_DATA_LEN(rhs_in, rhs_data, rhs_len); return MP_BOOL((op == RT_COMPARE_OP_IN) ^ (find_subbytes(lhs_data, lhs_len, rhs_data, rhs_len) == NULL)); } break; case RT_BINARY_OP_MULTIPLY: { if (!MP_OBJ_IS_SMALL_INT(rhs_in)) { return NULL; } int n = MP_OBJ_SMALL_INT_VALUE(rhs_in); byte *data; mp_obj_t s = mp_obj_str_builder_start(lhs_len * n, &data); mp_seq_multiply(lhs_data, sizeof(*lhs_data), lhs_len, n, data); return mp_obj_str_builder_end(s); } } return MP_OBJ_NULL; // op not supported }
mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args) { #if DEBUG_PRINT DEBUG_printf("__import__:\n"); for (mp_uint_t i = 0; i < n_args; i++) { DEBUG_printf(" "); mp_obj_print(args[i], PRINT_REPR); DEBUG_printf("\n"); } #endif mp_obj_t module_name = args[0]; mp_obj_t fromtuple = mp_const_none; mp_int_t level = 0; if (n_args >= 4) { fromtuple = args[3]; if (n_args >= 5) { level = MP_OBJ_SMALL_INT_VALUE(args[4]); } } mp_uint_t mod_len; const char *mod_str = mp_obj_str_get_data(module_name, &mod_len); if (level != 0) { // What we want to do here is to take name of current module, // chop <level> trailing components, and concatenate with passed-in // module name, thus resolving relative import name into absolue. // This even appears to be correct per // http://legacy.python.org/dev/peps/pep-0328/#relative-imports-and-name // "Relative imports use a module's __name__ attribute to determine that // module's position in the package hierarchy." level--; mp_obj_t this_name_q = mp_obj_dict_get(mp_globals_get(), MP_OBJ_NEW_QSTR(MP_QSTR___name__)); assert(this_name_q != MP_OBJ_NULL); #if MICROPY_CPYTHON_COMPAT if (MP_OBJ_QSTR_VALUE(this_name_q) == MP_QSTR___main__) { // This is a module run by -m command-line switch, get its real name from backup attribute this_name_q = mp_obj_dict_get(mp_globals_get(), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); } #endif mp_map_t *globals_map = mp_obj_dict_get_map(mp_globals_get()); mp_map_elem_t *elem = mp_map_lookup(globals_map, MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP); bool is_pkg = (elem != NULL); #if DEBUG_PRINT DEBUG_printf("Current module/package: "); mp_obj_print(this_name_q, PRINT_REPR); DEBUG_printf(", is_package: %d", is_pkg); DEBUG_printf("\n"); #endif mp_uint_t this_name_l; const char *this_name = mp_obj_str_get_data(this_name_q, &this_name_l); const char *p = this_name + this_name_l; if (!is_pkg) { // We have module, but relative imports are anchored at package, so // go there. chop_component(this_name, &p); } uint dots_seen = 0; while (level--) { chop_component(this_name, &p); dots_seen++; } if (dots_seen == 0 && level >= 1) { // http://legacy.python.org/dev/peps/pep-0328/#relative-imports-and-name // "If the module's name does not contain any package information // (e.g. it is set to '__main__') then relative imports are // resolved as if the module were a top level module, regardless // of where the module is actually located on the file system." // Supposedly this if catches this condition and resolve it properly // TODO: But nobody knows for sure. This condition happens when // package's __init__.py does something like "import .submod". So, // maybe we should check for package here? But quote above doesn't // talk about packages, it talks about dot-less module names. DEBUG_printf("Warning: no dots in current module name and level>0\n"); p = this_name + this_name_l; } else if (level != -1) { nlr_raise(mp_obj_new_exception_msg(&mp_type_ImportError, "Invalid relative import")); } uint new_mod_l = (mod_len == 0 ? (size_t)(p - this_name) : (size_t)(p - this_name) + 1 + mod_len); char *new_mod = alloca(new_mod_l); memcpy(new_mod, this_name, p - this_name); if (mod_len != 0) { new_mod[p - this_name] = '.'; memcpy(new_mod + (p - this_name) + 1, mod_str, mod_len); } qstr new_mod_q = qstr_from_strn(new_mod, new_mod_l); DEBUG_printf("Resolved base name for relative import: '%s'\n", qstr_str(new_mod_q)); if (new_mod_q == MP_QSTR_) { // CPython raises SystemError nlr_raise(mp_obj_new_exception_msg(&mp_type_ImportError, "cannot perform relative import")); } module_name = MP_OBJ_NEW_QSTR(new_mod_q); mod_str = new_mod; mod_len = new_mod_l; } // check if module already exists qstr module_name_qstr = mp_obj_str_get_qstr(module_name); mp_obj_t module_obj = mp_module_get(module_name_qstr); if (module_obj != MP_OBJ_NULL) { DEBUG_printf("Module already loaded\n"); // If it's not a package, return module right away char *p = strchr(mod_str, '.'); if (p == NULL) { return module_obj; } // If fromlist is not empty, return leaf module if (fromtuple != mp_const_none) { return module_obj; } // Otherwise, we need to return top-level package qstr pkg_name = qstr_from_strn(mod_str, p - mod_str); return mp_module_get(pkg_name); } DEBUG_printf("Module not yet loaded\n"); #if MICROPY_MODULE_FROZEN mp_lexer_t *lex = mp_find_frozen_module(mod_str, mod_len); if (lex != NULL) { module_obj = mp_obj_new_module(module_name_qstr); // if args[3] (fromtuple) has magic value False, set up // this module for command-line "-m" option (set module's // name to __main__ instead of real name). // TODO: Duplicated below too. if (fromtuple == mp_const_false) { mp_obj_module_t *o = module_obj; mp_obj_dict_store(o->globals, MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); } do_load_from_lexer(module_obj, lex, mod_str); return module_obj; } #endif uint last = 0; VSTR_FIXED(path, MICROPY_ALLOC_PATH_MAX) module_obj = MP_OBJ_NULL; mp_obj_t top_module_obj = MP_OBJ_NULL; mp_obj_t outer_module_obj = MP_OBJ_NULL; uint i; for (i = 1; i <= mod_len; i++) { if (i == mod_len || mod_str[i] == '.') { // create a qstr for the module name up to this depth qstr mod_name = qstr_from_strn(mod_str, i); DEBUG_printf("Processing module: %s\n", qstr_str(mod_name)); DEBUG_printf("Previous path: =%.*s=\n", vstr_len(&path), vstr_str(&path)); // find the file corresponding to the module name mp_import_stat_t stat; if (vstr_len(&path) == 0) { // first module in the dotted-name; search for a directory or file stat = find_file(mod_str, i, &path); } else { // latter module in the dotted-name; append to path vstr_add_char(&path, PATH_SEP_CHAR); vstr_add_strn(&path, mod_str + last, i - last); stat = stat_dir_or_file(&path); } DEBUG_printf("Current path: %.*s\n", vstr_len(&path), vstr_str(&path)); if (stat == MP_IMPORT_STAT_NO_EXIST) { #if MICROPY_MODULE_WEAK_LINKS // check if there is a weak link to this module if (i == mod_len) { mp_map_elem_t *el = mp_map_lookup((mp_map_t*)&mp_builtin_module_weak_links_map, MP_OBJ_NEW_QSTR(mod_name), MP_MAP_LOOKUP); if (el == NULL) { goto no_exist; } // found weak linked module module_obj = el->value; } else { no_exist: #else { #endif // couldn't find the file, so fail if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { nlr_raise(mp_obj_new_exception_msg(&mp_type_ImportError, "module not found")); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "no module named '%q'", mod_name)); } } } else { // found the file, so get the module module_obj = mp_module_get(mod_name); } if (module_obj == MP_OBJ_NULL) { // module not already loaded, so load it! module_obj = mp_obj_new_module(mod_name); // if args[3] (fromtuple) has magic value False, set up // this module for command-line "-m" option (set module's // name to __main__ instead of real name). if (i == mod_len && fromtuple == mp_const_false) { mp_obj_module_t *o = module_obj; mp_obj_dict_store(o->globals, MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); #if MICROPY_CPYTHON_COMPAT // Store real name in "__main__" attribute. Choosen semi-randonly, to reuse existing qstr's. mp_obj_dict_store(o->globals, MP_OBJ_NEW_QSTR(MP_QSTR___main__), MP_OBJ_NEW_QSTR(mod_name)); #endif } if (stat == MP_IMPORT_STAT_DIR) { DEBUG_printf("%.*s is dir\n", vstr_len(&path), vstr_str(&path)); // https://docs.python.org/3/reference/import.html // "Specifically, any module that contains a __path__ attribute is considered a package." mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path), false)); vstr_add_char(&path, PATH_SEP_CHAR); vstr_add_str(&path, "__init__.py"); if (mp_import_stat(vstr_null_terminated_str(&path)) != MP_IMPORT_STAT_FILE) { vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py mp_warning("%s is imported as namespace package", vstr_str(&path)); } else { do_load(module_obj, &path); vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py } } else { // MP_IMPORT_STAT_FILE do_load(module_obj, &path); // TODO: We cannot just break here, at the very least, we must execute // trailer code below. But otherwise if there're remaining components, // that would be (??) object path within module, not modules path within FS. // break; } } if (outer_module_obj != MP_OBJ_NULL) { qstr s = qstr_from_strn(mod_str + last, i - last); mp_store_attr(outer_module_obj, s, module_obj); } outer_module_obj = module_obj; if (top_module_obj == MP_OBJ_NULL) { top_module_obj = module_obj; } last = i + 1; } }