mp_obj_t mp_obj_tuple_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) { mp_obj_tuple_t *o = lhs; switch (op) { case MP_BINARY_OP_ADD: { if (!mp_obj_is_subclass_fast(mp_obj_get_type(rhs), (mp_obj_t)&mp_type_tuple)) { return MP_OBJ_NULL; // op not supported } mp_obj_tuple_t *p = rhs; mp_obj_tuple_t *s = mp_obj_new_tuple(o->len + p->len, NULL); mp_seq_cat(s->items, o->items, o->len, p->items, p->len, mp_obj_t); return s; } case MP_BINARY_OP_MULTIPLY: { mp_int_t n; if (!mp_obj_get_int_maybe(rhs, &n)) { return MP_OBJ_NULL; // op not supported } if (n <= 0) { return mp_const_empty_tuple; } mp_obj_tuple_t *s = mp_obj_new_tuple(o->len * n, NULL); mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items); return s; } case MP_BINARY_OP_EQUAL: case MP_BINARY_OP_LESS: case MP_BINARY_OP_LESS_EQUAL: case MP_BINARY_OP_MORE: case MP_BINARY_OP_MORE_EQUAL: return MP_BOOL(tuple_cmp_helper(op, lhs, rhs)); default: return MP_OBJ_NULL; // op not supported } }
STATIC mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { mp_obj_list_t *o = lhs; switch (op) { case MP_BINARY_OP_SUBSCR: { #if MICROPY_ENABLE_SLICE if (MP_OBJ_IS_TYPE(rhs, &mp_type_slice)) { machine_uint_t start, stop; if (!m_seq_get_fast_slice_indexes(o->len, rhs, &start, &stop)) { assert(0); } mp_obj_list_t *res = list_new(stop - start); m_seq_copy(res->items, o->items + start, res->len, mp_obj_t); return res; } #endif uint index = mp_get_index(o->base.type, o->len, rhs, false); return o->items[index]; } case MP_BINARY_OP_ADD: { if (!MP_OBJ_IS_TYPE(rhs, &mp_type_list)) { return NULL; } mp_obj_list_t *p = rhs; mp_obj_list_t *s = list_new(o->len + p->len); m_seq_cat(s->items, o->items, o->len, p->items, p->len, mp_obj_t); return s; } case MP_BINARY_OP_INPLACE_ADD: { if (!MP_OBJ_IS_TYPE(rhs, &mp_type_list)) { return NULL; } list_extend(lhs, rhs); return o; } case MP_BINARY_OP_MULTIPLY: { machine_int_t n; if (!mp_obj_get_int_maybe(rhs, &n)) { return NULL; } mp_obj_list_t *s = list_new(o->len * n); mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items); return s; } case MP_BINARY_OP_EQUAL: case MP_BINARY_OP_LESS: case MP_BINARY_OP_LESS_EQUAL: case MP_BINARY_OP_MORE: case MP_BINARY_OP_MORE_EQUAL: return MP_BOOL(list_cmp_helper(op, lhs, rhs)); case MP_BINARY_OP_NOT_EQUAL: return MP_BOOL(!list_cmp_helper(MP_BINARY_OP_EQUAL, lhs, rhs)); default: // op not supported return NULL; } }
// Convert an index into a pointer to its lead byte. Out of bounds indexing will raise IndexError or // be capped to the first/last character of the string, depending on is_slice. const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, size_t self_len, mp_obj_t index, bool is_slice) { (void)type; mp_int_t i; // Copied from mp_get_index; I don't want bounds checking, just give me // the integer as-is. (I can't bounds-check without scanning the whole // string; an out-of-bounds index will be caught in the loops below.) if (MP_OBJ_IS_SMALL_INT(index)) { i = MP_OBJ_SMALL_INT_VALUE(index); } else if (!mp_obj_get_int_maybe(index, &i)) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "string indices must be integers, not %s", mp_obj_get_type_str(index))); } const byte *s, *top = self_data + self_len; if (i < 0) { // Negative indexing is performed by counting from the end of the string. for (s = top - 1; i; --s) { if (s < self_data) { if (is_slice) { return self_data; } nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "string index out of range")); } if (!UTF8_IS_CONT(*s)) { ++i; } } ++s; } else if (!i) { return self_data; // Shortcut - str[0] is its base pointer } else { // Positive indexing, correspondingly, counts from the start of the string. // It's assumed that negative indexing will generally be used with small // absolute values (eg str[-1], not str[-1000000]), which means it'll be // more efficient this way. for (s = self_data; true; ++s) { if (s >= top) { if (is_slice) { return top; } nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "string index out of range")); } while (UTF8_IS_CONT(*s)) { ++s; } if (!i--) { return s; } } } return s; }
STATIC mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { mp_obj_list_t *o = MP_OBJ_TO_PTR(lhs); switch (op) { case MP_BINARY_OP_ADD: { if (!MP_OBJ_IS_TYPE(rhs, &mp_type_list)) { return MP_OBJ_NULL; // op not supported } mp_obj_list_t *p = MP_OBJ_TO_PTR(rhs); mp_obj_list_t *s = list_new(o->len + p->len); mp_seq_cat(s->items, o->items, o->len, p->items, p->len, mp_obj_t); return MP_OBJ_FROM_PTR(s); } case MP_BINARY_OP_INPLACE_ADD: { list_extend(lhs, rhs); return lhs; } case MP_BINARY_OP_MULTIPLY: { mp_int_t n; if (!mp_obj_get_int_maybe(rhs, &n)) { return MP_OBJ_NULL; // op not supported } if (n < 0) { n = 0; } mp_obj_list_t *s = list_new(o->len * n); mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items); return MP_OBJ_FROM_PTR(s); } case MP_BINARY_OP_EQUAL: case MP_BINARY_OP_LESS: case MP_BINARY_OP_LESS_EQUAL: case MP_BINARY_OP_MORE: case MP_BINARY_OP_MORE_EQUAL: { if (!MP_OBJ_IS_TYPE(rhs, &mp_type_list)) { if (op == MP_BINARY_OP_EQUAL) { return mp_const_false; } return MP_OBJ_NULL; // op not supported } mp_obj_list_t *another = MP_OBJ_TO_PTR(rhs); bool res = mp_seq_cmp_objs(op, o->items, o->len, another->items, another->len); return mp_obj_new_bool(res); } default: return MP_OBJ_NULL; // op not supported } }
// If exc is SystemExit, return value where FORCED_EXIT bit set, // and lower 8 bits are SystemExit value. For all other exceptions, // return 1. STATIC int handle_uncaught_exception(mp_obj_t exc) { // check for SystemExit if (mp_obj_is_subclass_fast(mp_obj_get_type(exc), &mp_type_SystemExit)) { // None is an exit value of 0; an int is its value; anything else is 1 mp_obj_t exit_val = mp_obj_exception_get_value(exc); mp_int_t val = 0; if (exit_val != mp_const_none && !mp_obj_get_int_maybe(exit_val, &val)) { val = 1; } return FORCED_EXIT | (val & 255); } // Report all other exceptions mp_obj_print_exception(&mp_stderr_print, exc); return 1; }
STATIC mp_obj_t list_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) { mp_obj_list_t *o = lhs; switch (op) { case MP_BINARY_OP_ADD: { if (!MP_OBJ_IS_TYPE(rhs, &mp_type_list)) { return MP_OBJ_NULL; // op not supported } mp_obj_list_t *p = rhs; mp_obj_list_t *s = list_new(o->len + p->len); mp_seq_cat(s->items, o->items, o->len, p->items, p->len, mp_obj_t); return s; } case MP_BINARY_OP_INPLACE_ADD: { if (!MP_OBJ_IS_TYPE(rhs, &mp_type_list)) { return MP_OBJ_NULL; // op not supported } list_extend(lhs, rhs); return o; } case MP_BINARY_OP_MULTIPLY: { mp_int_t n; if (!mp_obj_get_int_maybe(rhs, &n)) { return MP_OBJ_NULL; // op not supported } if (n < 0) { n = 0; } mp_obj_list_t *s = list_new(o->len * n); mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items); return s; } case MP_BINARY_OP_EQUAL: case MP_BINARY_OP_LESS: case MP_BINARY_OP_LESS_EQUAL: case MP_BINARY_OP_MORE: case MP_BINARY_OP_MORE_EQUAL: return MP_BOOL(list_cmp_helper(op, lhs, rhs)); default: return MP_OBJ_NULL; // op not supported } }
// 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; }
// returns standard error codes: 0 for success, 1 for all other errors STATIC int execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bool is_repl) { if (lex == NULL) { return 1; } if (0) { // just tokenise while (!mp_lexer_is_kind(lex, MP_TOKEN_END)) { mp_token_show(mp_lexer_cur(lex)); mp_lexer_to_next(lex); } mp_lexer_free(lex); return 0; } mp_parse_error_kind_t parse_error_kind; mp_parse_node_t pn = mp_parse(lex, input_kind, &parse_error_kind); if (pn == MP_PARSE_NODE_NULL) { // parse error mp_parse_show_exception(lex, parse_error_kind); mp_lexer_free(lex); return 1; } qstr source_name = mp_lexer_source_name(lex); #if MICROPY_PY___FILE__ if (input_kind == MP_PARSE_FILE_INPUT) { mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); } #endif mp_lexer_free(lex); /* printf("----------------\n"); mp_parse_node_print(pn, 0); printf("----------------\n"); */ mp_obj_t module_fun = mp_compile(pn, source_name, emit_opt, is_repl); if (module_fun == mp_const_none) { // compile error return 1; } if (compile_only) { return 0; } // execute it nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_call_function_0(module_fun); nlr_pop(); return 0; } else { // uncaught exception // check for SystemExit mp_obj_t exc = (mp_obj_t)nlr.ret_val; if (mp_obj_is_subclass_fast(mp_obj_get_type(exc), &mp_type_SystemExit)) { mp_obj_t exit_val = mp_obj_exception_get_value(exc); mp_int_t val; if (!mp_obj_get_int_maybe(exit_val, &val)) { val = 0; } exit(val); } mp_obj_print_exception((mp_obj_t)nlr.ret_val); return 1; } }
// Convert an index into a pointer to its lead byte. Out of bounds indexing will raise IndexError or // be capped to the first/last character of the string, depending on is_slice. const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, size_t self_len, mp_obj_t index, bool is_slice) { // All str functions also handle bytes objects, and they call str_index_to_ptr(), // so it must handle bytes. if (type == &mp_type_bytes) { // Taken from objstr.c:str_index_to_ptr() size_t index_val = mp_get_index(type, self_len, index, is_slice); return self_data + index_val; } mp_int_t i; // Copied from mp_get_index; I don't want bounds checking, just give me // the integer as-is. (I can't bounds-check without scanning the whole // string; an out-of-bounds index will be caught in the loops below.) if (MP_OBJ_IS_SMALL_INT(index)) { i = MP_OBJ_SMALL_INT_VALUE(index); } else if (!mp_obj_get_int_maybe(index, &i)) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "string indices must be integers, not %s", mp_obj_get_type_str(index))); } const byte *s, *top = self_data + self_len; if (i < 0) { // Negative indexing is performed by counting from the end of the string. for (s = top - 1; i; --s) { if (s < self_data) { if (is_slice) { return self_data; } mp_raise_msg(&mp_type_IndexError, "string index out of range"); } if (!UTF8_IS_CONT(*s)) { ++i; } } ++s; } else { // Positive indexing, correspondingly, counts from the start of the string. // It's assumed that negative indexing will generally be used with small // absolute values (eg str[-1], not str[-1000000]), which means it'll be // more efficient this way. s = self_data; while (1) { // First check out-of-bounds if (s >= top) { if (is_slice) { return top; } mp_raise_msg(&mp_type_IndexError, "string index out of range"); } // Then check completion if (i-- == 0) { break; } // Then skip UTF-8 char ++s; while (UTF8_IS_CONT(*s)) { ++s; } } } return s; }