microPython的源码解析之 objstr.c

MicroPython 是一种适用于微控制器和其他受限环境的 Python 编程语言的实现。它旨在提供与 Python 3 语言的紧密兼容,同时考虑到内存和计算资源的限制。MicroPython 库是这门语言的核心组成部分,提供了一系列的模块和函数,使得开发者能够在硬件上执行各种任务。
下面将通过系列文章,逐一解读microPython,以便让读者了解掌握microPython的整个核心逻辑.,以便读者可以透过这个Python的最小内核,掌握Python解析器的核心实现逻辑,学习世界上最优秀的源码设计之一.


microPython Python最小内核源码解析
NI-motion运动控制c语言示例代码解析
python编程示例系列 python编程示例系列二
python的Web神器Streamlit


以下是代码的完整版,包括翻译的中文注释和一些额外的注释说明:

#include <string.h>
#include <assert.h>

#include "py/unicode.h"
#include "py/objstr.h"
#include "py/objlist.h"
#include "py/runtime.h"
#include "py/stackctrl.h"

#if MICROPY_PY_BUILTINS_STR_OP_MODULO
// 如果启用了字符串的模运算符操作
static mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_t *args, mp_obj_t dict);
#endif

// 创建一个新的字节迭代器对象
static mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf);
// 抛出异常,因为隐式类型转换不合法
static NORETURN void bad_implicit_conversion(mp_obj_t self_in);

// 根据vstr创建一个新的字符串类型对象
static mp_obj_t mp_obj_new_str_type_from_vstr(const mp_obj_type_t *type, vstr_t *vstr);

// 检查参数类型是否与对象类型相匹配
static void str_check_arg_type(const mp_obj_type_t *self_type, const mp_obj_t arg) {
   
    // 字符串操作通常需要参数类型与调用它们的字符串类型相匹配
    // 例如 str.find(str), byte.startswith(byte)
    // 但字节数组可以用作字节字符串,反之亦然
    #if MICROPY_PY_BUILTINS_BYTEARRAY
    if (arg_type == &mp_type_bytearray) {
   
        arg_type = &mp_type_bytes;
    }
    if (self_type == &mp_type_bytearray) {
   
        self_type = &mp_type_bytes;
    }
    #endif

    if (arg_type != self_type) {
   
        bad_implicit_conversion(arg);
    }
}

// 检查对象是否为字符串或字节类型
static void check_is_str_or_bytes(mp_obj_t self_in) {
   
    mp_check_self(mp_obj_is_str_or_bytes(self_in));
}

// 打印带引号的字符串
void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t str_len, bool is_bytes) {
   
    // 此函数会转义字符,但打印速度会很慢(需要多次调用打印函数)
    bool has_single_quote = false;
    bool has_double_quote = false;
    for (const byte *s = str_data, *top = str_data + str_len; !has_double_quote && s < top; s++) {
   
        if (*s == '\'') {
   
            has_single_quote = true;
        } else if (*s == '"') {
   
            has_double_quote = true;
        }
    }
    int quote_char = '\'';
    if (has_single_quote && !has_double_quote) {
   
        quote_char = '"';
    }
    mp_printf(print, "%c", quote_char);
    for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) {
   
        if (*s == quote_char) {
   
            mp_printf(print, "\\%c", quote_char);
        } else if (*s == '\\') {
   
            mp_print_str(print, "\\\\");
        } else if (*s >= 0x20 && *s != 0x7f && (!is_bytes || *s < 0x80)) {
   
            // 在字符串中,任何非ASCII控制字符都会被原样打印
            mp_printf(print, "%c", *s);
        } else if (*s == '\n') {
   
            mp_print_str(print, "\\n");
        } else if (*s == '\r') {
   
            mp_print_str(print, "\\r");
        } else if (*s == '\t') {
   
            mp_print_str(print, "\\t");
        } else {
   
            mp_printf(print, "\\x%02x", *s);
        }
    }
    mp_printf(print, "%c", quote_char);
}

#if MICROPY_PY_JSON
// 打印JSON格式的字符串
void mp_str_print_json(const mp_print_t *print, const byte *str_data, size_t str_len) {
   
    // 根据JSON规范打印字符串,详情见 http://www.ietf.org/rfc/rfc4627.txt
    mp_print_str(print, "\"");
    for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) {
   
        if (*s == '"' || *s == '\\') {
   
            mp_printf(print, "\\%c", *s);
        } else if (*s >= 32) {
   
            // 这将处理普通字符和UTF-8编码的字符
            mp_printf(print, "%c", *s);
        } else if (*s == '\n') {
   
            mp_print_str(print, "\\n");
        } else if (*s == '\r') {
   
            mp_print_str(print, "\\r");
        } else if (*s == '\t') {
   
            mp_print_str(print, "\\t");
        } else {
   
            // 这将处理控制字符
            mp_printf(print, "\\u%04x", *s);
        }
    }
    mp_print_str(print, "\"");
}
#endif

// 打印字符串
static void str_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
   
    GET_STR_DATA_LEN(self_in, str_data, str_len);
    #if MICROPY_PY_JSON
    if (kind == PRINT_JSON) {
   
        mp_str_print_json(print, str_data, str_len);
        return;
    }
    #endif
    #if !MICROPY_PY_BUILTINS_STR_UNICODE
    // 如果没有启用Unicode支持,则判断是否为字节类型
    bool is_bytes = mp_obj_is_type(self_in, &mp_type_bytes);
    #else
    bool is_bytes = true;
    #endif
    if (kind == PRINT_RAW || (!MICROPY_PY_BUILTINS_STR_UNICODE && kind == PRINT_STR && !is_bytes)) {
   
        print->print_strn(print->data, (const char *)str_data, str_len);
    } else {
   
        if (is_bytes) {
   
            print->print_strn(print->data, "b", 1);
        }
        mp_str_print_quoted(print, str_data, str_len, is_bytes);
    }
}

// 创建新的字符串对象
mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
   
    #if MICROPY_CPYTHON_COMPAT
    // 兼容CPython的关键字参数
    if (n_kw != 0) {
   
        mp_arg_error_unimpl_kw();
    }
    #endif

    mp_arg_check_num(n_args, n_kw, 0, 3, false);

    // 根据参数数量选择创建字符串的方式
    switch (n_args) {
   
        case 0:
            return MP_OBJ_NEW_QSTR(MP_QSTR_);
        case 1: {
   
            // 从单个参数创建字符串
            vstr_t vstr;
            mp_print_t print;
            vstr_init_print(&vstr, 16, &print);
            mp_obj_print_helper(&print, args[0], PRINT_STR);
            return mp_obj_new_str_type_from_vstr(type, &vstr);
        }
        default: // 2 或 3 个参数
            // 验证第二个和第三个参数
            if (mp_obj_is_type(args[0], &mp_type_bytes)) {
   
                // 处理字节类型的参数
                GET_STR_DATA_LEN(args[0], str_data, str_len);
                GET_STR_HASH(args[0], str_hash);
                if (str_hash == 0) {
   
                    str_hash = qstr_compute_hash(str_data, str_len);
                }
                #if MICROPY_PY_BUILTINS_STR_UNICODE_CHECK
                // 检查UTF-8编码
                if (!utf8_check(str_data, str_len)) {
   
                    mp_raise_msg(&mp_type_UnicodeError, NULL);
                }
                #endif

                // 查找是否存在相同的qstr
                qstr q = qstr_find_strn((const char *)str_data, str_len);
                if (q != MP_QSTRnull) {
   
                    return MP_OBJ_NEW_QSTR(q);
                }

                mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_copy(type, NULL, str_len));
                o->data = str_data;
                o->hash = str_hash;
                return MP_OBJ_FROM_PTR(o);
            } else {
   
                // 处理其他类型的参数
                mp_buffer_info_t bufinfo;
                mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
                // 这将检查输入的UTF-8编码
                return mp_obj_new_str(bufinfo.buf, bufinfo.len);
            }
    }
}

// 创建新的字节对象
static mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
   
    (void)type_in;

    #if MICROPY_CPYTHON_COMPAT
    // 兼容CPython的关键字参数
    if (n_kw != 0) {
   
        mp_arg_error_unimpl_kw();
    }
    #else
    (void)n_kw;
    #endif

    if (n_args == 0) {
   
        return mp_const_empty_bytes;
    }

    if (mp_obj_is_type(args[0], &mp_type_bytes)) {
   
        // 如果参数已经是字节类型,则直接返回
        return args[0];
    }

    if (mp_obj_is_str(args[0])) {
   
        // 如果参数是字符串类型
        if (n_args < 2 || n_args > 3) {
   
            #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
            goto wrong_args;
            #else
            mp_raise_TypeError(MP_ERROR_TEXT("string argument without an encoding"));
            #endif
        }
        GET_STR_DATA_LEN(args[0], str_data, str_len);
        GET_STR_HASH(args[0], str_hash);
        if (str_hash == 0) {
   
            str_hash = qstr_compute_hash(str_data, str_len);
        }
        #if MICROPY_PY_BUILTINS_STR_UNICODE_CHECK
        // 检查UTF-8编码
        if (!utf8_check(str_data, str_len)) {
   
            mp_raise_msg(&mp_type_UnicodeError, NULL);
        }
        #endif

        // 查找是否存在相同的qstr
        qstr q = qstr_find_strn((const char *)str_data, str_len);
        if (q != MP_QSTRnull) {
   
            return MP_OBJ_NEW_QSTR(q);
        }

        mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_copy(&mp_type_bytes, NULL, str_len));
        o->data = str_data;
        o->hash = str_hash;
        return MP_OBJ_FROM_PTR(o);
    }

    if (n_args > 1) {
   
        goto wrong_args;
    }

    if (mp_obj_is_small_int(args[0])) {
   
        // 如果参数是小整数类型
        mp_int_t len = MP_OBJ_SMALL_INT_VALUE(args[0]);
        if (len < 0) {
   
            mp_raise_ValueError(NULL);
        }
        vstr_t vstr;
        vstr_init_len(&vstr, len);
        memset(vstr.buf, 0, len);
        return mp_obj_new_bytes_from_vstr(&vstr);
    }

    // 检查参数是否支持缓冲协议
    mp_buffer_info_t bufinfo;
    if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_READ)) {
   
        return mp_obj_new_bytes(bufinfo.buf, bufinfo.len);
    }

    vstr_t vstr;
    // 如果初始化长度已知,则尝试创建长度精确的数组
    mp_obj_t len_in = mp_obj_len_maybe(args[0]);
    if (len_in == MP_OBJ_NULL) {
   
        vstr_init(&vstr, 16);
    } else {
   
        mp_int_t len = MP_OBJ_SMALL_INT_VALUE(len_in);
        vstr_init(&vstr, len);
    }

    mp_obj_iter_buf_t iter_buf;
    mp_obj_t iterable = mp_getiter(args[0], &iter_buf);
    mp_obj_t item;
    while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
   
        mp_int_t val = mp_obj_get_int(item);
        #if MICROPY_FULL_CHECKS
        // 检查值是否在字节范围内
        if (val < 0 || val > 255) {
   
            mp_raise_ValueError(MP_ERROR_TEXT("bytes value out of range"));
        }
        #endif
        vstr_add_byte(&vstr, val);
    }

    return mp_obj_new_bytes_from_vstr(&vstr);

wrong_args:
    // 参数数量不正确
    mp_raise_TypeError(MP_ERROR_TEXT("wrong number of arguments"));
}

// 查找子字节串
// 与strstr类似,但是可以指定长度,并且允许\0字节
// 可以根据指定的方向(正向或反向)在haystack中查找needle
const byte *find_subbytes(const byte *haystack, size_t hlen, const byte *needle, size_t nlen, int direction) {
   
    if (hlen >= nlen) {
   
        size_t str_index, str_index_end;
        if (direction > 0) {
   
            str_index = 0;
            str_index_end = hlen - nlen;
        } else {
   
            str_index = hlen - nlen;
            str_index_end = 0;
        }
        for (;;) {
   
            if (memcmp(&haystack[str_index], needle, nlen) == 0) {
   
                // 找到匹配的子字节串
                return haystack + str_index;
            }
            if (str_index == str_index_end) {
   
                // 未找到
                break;
            }
            str_index += direction;
        }
    }
    return NULL;
}

// 字符串或字节类型的二元操作
mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
   
    // 检查是否为模运算符操作
    if (op == MP_BINARY_OP_MODULO) {
   
        #if MICROPY_PY_BUILTINS_STR_OP_MODULO
        // 处理模运算符操作
        mp_obj_t *args = &rhs_in;
        size_t n_args = 1;
        mp_obj_t dict = MP_OBJ_NULL;
        if (mp_obj_is_type(rhs_in, &mp_type_tuple)) {
   
            // 处理元组类型的参数
            mp_obj_tuple_get(rhs_in, &n_args, &args);
        } else if (mp_obj_is_type(rhs_in, &mp_type_dict)) {
   
            // 处理字典类型的参数
            dict = rhs_in;
        }
        return str_modulo_format(lhs_in, n_args, args, dict);
        #else
        return MP_OBJ_NULL;
        #endif
    }

    // 从现在起我们需要lhs的类型和数据,所以提取它们
    const mp_obj_type_t *lhs_type = mp_obj_get_type(lhs_in);
    GET_STR_DATA_LEN(lhs_in, lhs_data, lhs_len);

    // 检查是否为乘法操作
    if (op == MP_BINARY_OP_MULTIPLY) {
   
        mp_int_t n;
        if (!mp_obj_get_int_maybe(rhs_in, &n)) {
   
            return MP_OBJ_NULL; // 操作不支持
        }
        if (n <= 0) {
   
            if (lhs_type == &mp_type_str) {
   
                // 返回空字符串
                return MP_OBJ_NEW_QSTR(MP_QSTR_);
            } else {
   
                // 返回空字节对象
                return mp_const_empty_bytes;
            }
        }
        vstr_t vstr;
        vstr_init_len(&vstr, lhs_len * n);
        mp_seq_multiply(lhs_data, sizeof(*lhs_data), lhs_len, n, vstr.buf);
        return mp_obj_new_str_type_from_vstr(lhs_type, &vstr);
    }

    // 从现在起所有操作都允许:
    //    - 字符串与字符串
    //    - 字节与字节
    //    - 字节与字节数组
    //    - 字节与array.array
    // 为了高效地执行这些操作,我们使用缓冲协议提取rhs的原始数据,
    // 但仅当lhs是字节对象时。

    const byte *rhs_data;
    size_t rhs_len;
    if (lhs_type == mp_obj_get_type(rhs_in)) {
   
        // 如果左右操作数类型相同,直接获取数据
        GET_STR_DATA_LEN(rhs_in, rhs_data_, rhs_len_);
        rhs_data = rhs_data_;
        rhs_len = rhs_len_;
    } else if (lhs_type == &mp_type_bytes) {
   
        // 如果lhs是字节类型,rhs必须支持缓冲协议
        mp_buffer_info_t bufinfo;
        if (!mp_get_buffer(rhs_in, &bufinfo, MP_BUFFER_READ)) {
   
            return MP_OBJ_NULL; // 操作不支持
        }
        rhs_data = bufinfo.buf;
        rhs_len = bufinfo.len;
    } else {
   
        // 如果lhs是字符串类型,rhs类型不兼容
        // (除了相等操作,因为mp_obj_equal()会处理这种情况)
        // 其他所有操作都不支持,可能会由其他类型处理,例如反向操作。

        // CONTAINS操作必须抛出bad-implicit-conversion异常,因为
        // 否则mp_binary_op()会回退到`list(lhs).__contains__(rhs)`。
        if (op == MP_BINARY_OP_CONTAINS) {
   
            bad_implicit_conversion(rhs_in);
        }

        // 所有其他操作都不支持,可以由其他类型处理。
        return MP_OBJ_NULL;
    }

    // 根据操作符执行相应的操作
    switch (op) {
   
        case MP_BINARY_OP_ADD:
        case MP_BINARY_OP_INPLACE_ADD: {
   
            // 处理加法操作
            if (lhs_len == 0 && mp_obj_get_type(rhs_in) == lhs_type) {
   
                return rhs_in;
            }
            if (rhs_len == 0) {
   
                return lhs_in;
            }

            vstr_t vstr;
            vstr_init_len(&vstr, lhs_len + rhs_len);
            memcpy(vstr.buf, lhs_data, lhs_len);
            memcpy(vstr.buf + lhs_len, rhs_data,rhs_len);
            return mp_obj_new_str_type_from_vstr(lhs_type, &vstr);
        }

        case MP_BINARY_OP_CONTAINS:
            // 检查是否包含子字节串
            return mp_obj_new_bool(find_subbytes(lhs_data, lhs_len, rhs_data, rhs_len, 1) != NULL);

        // case MP_BINARY_OP_NOT_EQUAL: // 这里永远不会传入这个操作
        case MP_BINARY_OP_EQUAL: // 这将只为字节传入,字符串在mp_obj_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_obj_new_bool(mp_seq_cmp_bytes(op, lhs_data, lhs_len, rhs_data, rhs_len));

        default:
            // 操作不支持
            return MP_OBJ_NULL;
    }
}

#if !MICROPY_PY_BUILTINS_STR_UNICODE
// objstrunicode定义了自己的版本
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) {
   
    // 根据索引获取指向字符串中特定位置的指针
    size_t index_val = mp_get_index(type, self_len, index, is_slice);
    return self_data + index_val;
}
#endif

// 字节或字符串的索引操作
static mp_obj_t bytes_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
   
    const mp_obj_type_t *type = mp_obj_get_type(self_in);
    GET_STR_DATA_LEN(self_in, self_data, self_len);
    if (value == MP_OBJ_SENTINEL) {
   
        // 加载操作
        #if MICROPY_PY_BUILTINS_SLICE
        if (mp_obj_is_type(index, &mp_type_slice)) {
   
            // 处理切片操作
            mp_bound_slice_t slice;
            if (!mp_seq_get_fast_slice_indexes(self_len, index, &slice)) {
   
                mp_raise_NotImplementedError(MP_ERROR_TEXT("only slices with step=1 (aka None) are supported"));
            }
            return mp_obj_new_str_of_type(type, self_data + slice.start, slice.stop - slice.start);
        }
        #endif
        size_t index_val = mp_get_index(type, self_len, index, false);
        // 如果启用了Unicode支持,则类型总是字节,所以采取捷径
        if (MICROPY_PY_BUILTINS_STR_UNICODE || type == &mp_type_bytes) {
   
            return MP_OBJ_NEW_SMALL_INT(self_data[index_val]);
        } else {
   
            return mp_obj_new_str_via_qstr((char *)&self_data[index_val], 1);
        }
    } else {
   
        // 赋值操作不支持
        return MP_OBJ_NULL;
    }
}

// 字符串连接操作
static mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) {
   
    check_is_str_or_bytes(self_in);
    const mp_obj_type_t *self_type = mp_obj_get_type(self_in);
    const mp_obj_type_t *ret_type = self_type;

    // 获取分隔符字符串
    GET_STR_DATA_LEN(self_in, sep_str, sep_len);

    // 处理参数
    size_t seq_len;
    mp_obj_t *seq_items;

    if (!mp_obj_is_type(arg, &mp_type_list) && !mp_obj_is_type(arg, &mp_type_tuple)) {
   
        // 参数不是列表也不是元组,尝试将其转换为列表
        arg = mp_obj_list_make_new(&mp_type_list, 1, 0, &arg);
    }
    mp_obj_get_array(arg, &seq_len, &seq_items);

    // 计算所需长度
    size_t required_len = 0;
    #if MICROPY_PY_BUILTINS_BYTEARRAY
    if (self_type == &mp_type_bytearray) {
   
        self_type = &mp_type_bytes;
    }
    #endif
    for (size_t i = 0; i < seq_len; i++) {
   
        const mp_obj_type_t *seq_type = mp_obj_get_type(seq_items[i]);
        #if MICROPY_PY_BUILTINS_BYTEARRAY
        if (seq_type == &mp_type_bytearray) {
   
            seq_type = &mp_type_bytes;
        }
        #endif
        if (seq_type != self_type) {
   
            // 参数类型不匹配
            mp_raise_TypeError(
                MP_ERROR_TEXT("join expects a list of str/bytes objects consistent with self object"));
        }
        if (i > 0) {
   
            required_len += sep_len;
        }
        GET_STR_LEN(seq_items[i], l);
        required_len += l;
    }

    // 创建连接后的字符串
    vstr_t vstr;
    vstr_init_len(&vstr, required_len);
    byte *data = (byte *)vstr.buf;
    for (size_t i = 0; i < seq_len; i++) {
   
        if (i > 0) {
   
            memcpy(data, sep_str, sep_len);
            data += sep_len;
        }
        GET_STR_DATA_LEN(seq_items[i], s, l);
        memcpy(data, s, l);
        data += l;
    }

    // 返回连接后的字符串
    return mp_obj_new_str_type_from_vstr(ret_type, &vstr);
}
MP_DEFINE_CONST_FUN_OBJ_2(str_join_obj, str_join);

// 字符串分割操作
mp_obj_t mp_obj_str_split(size_t n_args, const mp_obj_t *args) {
   
    const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
    mp_int_t splits = -1;
    mp_obj_t sep = mp_const_none;
    if (n_args > 1) {
   
        sep = args[1];
        if (n_args > 2) {
   
            splits = mp_obj_get_int(args[2]);
        }
    }

    mp_obj_t res = mp_obj_new_list(0, NULL);
    GET_STR_DATA_LEN(args[0], s, len);
    const byte *top = s + len;

    if (sep == mp_const_none) {
   
        // 未给出分隔符,根据空白字符分割
        // 初始空白字符不计入分割,所以预先处理
        while (s < top && unichar_isspace(*s)) {
   
   
  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

openwin_top

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值