microPython的源码解析之 obj.c

本文深入解析MicroPython的C语言实现,重点介绍对象处理相关函数,包括内存分配、类型检查、打印、比较和数值转换等。通过理解MicroPython的核心逻辑,帮助读者掌握Python解析器的设计和实现。同时,文章提及了NI-Motion的C语言示例,展示如何在运动控制器上执行各种任务。
摘要由CSDN通过智能技术生成

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

microPython Python最小内核源码解析

#include <stdint.h> // 定义用于整数类型支持的头文件
#include <stdio.h>   // 定义标准输入输出函数的头文件
#include <stdarg.h> // 定义可变参数列表支持的头文件
#include <assert.h>  // 定义断言检查的宏

// 包含MicroPython对象定义和类型系统的头文件
#include "py/obj.h"
#include "py/objtype.h"
#include "py/objint.h"
#include "py/objstr.h"
#include "py/runtime.h" // 包含MicroPython运行时环境的头文件
#include "py/stackctrl.h" // 包含栈控制的头文件
#include "py/stream.h"  // 包含流处理功能,用于mp_obj_print函数

// 为mp_obj_malloc{,_var}宏分配对象并设置类型
MP_NOINLINE void *mp_obj_malloc_helper(size_t num_bytes, const mp_obj_type_t *type) {
   
    mp_obj_base_t *base = (mp_obj_base_t *)m_malloc(num_bytes); // 分配内存并转换为mp_obj_base_t类型的指针
    base->type = type; // 设置对象的类型
    return base; // 返回新分配对象的指针
}

#if MICROPY_ENABLE_FINALISER
// 为mp_obj_malloc{,_var}_with_finaliser宏分配对象、设置类型并启用清理函数
MP_NOINLINE void *mp_obj_malloc_with_finaliser_helper(size_t num_bytes, const mp_obj_type_t *type) {
   
    mp_obj_base_t *base = (mp_obj_base_t *)m_malloc_with_finaliser(num_bytes); // 使用带清理功能的内存分配函数
    base->type = type; // 设置对象的类型
    return base; // 返回新分配对象的指针
}
#endif

// 获取对象类型的函数,用于mp_obj_get_type宏
const mp_obj_type_t *MICROPY_WRAP_MP_OBJ_GET_TYPE(mp_obj_get_type)(mp_const_obj_t o_in) {
   
    // 根据MicroPython的配置和对象的表示方式,选择不同的类型判断逻辑
    #if MICROPY_OBJ_IMMEDIATE_OBJS && MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A
    if (mp_obj_is_obj(o_in)) {
    // 检查输入是否为对象
        const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in); // 将对象转换为指针
        return o->type; // 返回对象的类型
    } else {
   
        static const mp_obj_type_t *const types[] = {
    // 定义一个类型数组,用于立即对象的类型判断
            NULL, &mp_type_int, &mp_type_str, &mp_type_int,
            NULL, &mp_type_int, &mp_type_NoneType, &mp_type_int,
            NULL, &mp_type_int, &mp_type_str, &mp_type_int,
            NULL, &mp_type_int, &mp_type_bool, &mp_type_int,
        };
        return types[(uintptr_t)o_in & 0xf]; // 使用掩码操作和指针值来选择对应的类型
    }

    #elif MICROPY_OBJ_IMMEDIATE_OBJS && MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
    if (mp_obj_is_small_int(o_in)) {
    // 检查输入是否为小整数
        return &mp_type_int; // 如果是小整数,返回整数类型
    } else if (mp_obj_is_obj(o_in)) {
   
        const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in); // 将对象转换为指针
        return o->type; // 返回对象的类型
    }
    #if MICROPY_PY_BUILTINS_FLOAT
    // 如果配置了浮点数支持,检查输入是否为浮点数
    else if ((((mp_uint_t)(o_in)) & 0xff800007) != 0x00000006) {
   
        return &mp_type_float;
    }
    #endif
    // 定义一个类型数组,用于立即对象的类型判断
    static const mp_obj_type_t *const types[] = {
   
        &mp_type_str, &mp_type_NoneType, &mp_type_str, &mp_type_bool,
    };
    return types[((uintptr_t)o_in >> 3) & 3]; // 使用位移和掩码操作来选择对应的类型
    #else
    // 通用的对象类型判断逻辑
    if (mp_obj_is_small_int(o_in)) {
    // 检查输入是否为小整数
        return &mp_type_int; // 如果是小整数,返回整数类型
    } else if (mp_obj_is_qstr(o_in)) {
    // 检查输入是否为qstr(快速字符串)
        return &mp_type_str; // 如果是qstr,返回字符串类型
    }
    #if MICROPY_PY_BUILTINS_FLOAT && ( \
        MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D)
    // 如果配置了浮点数支持,并且对象表示方式为C或D
    else if (mp_obj_is_float(o_in)) {
    // 检查输入是否为浮点数
        return &mp_type_float; // 如果是浮点数,返回浮点数类型
    }
    #endif
    #if MICROPY_OBJ_IMMEDIATE_OBJS
    // 如果配置了立即对象支持
    else if (mp_obj_is_immediate_obj(o_in)) {
    // 检查输入是否为立即对象
        static const mp_obj_type_t *const types[2] = {
   &mp_type_NoneType, &mp_type_bool}; // 定义一个类型数组,用于立即对象的类型判断
        return types[MP_OBJ_IMMEDIATE_OBJ_VALUE(o_in) & 1]; // 使用位操作来选择对应的类型
    }
    #endif
    // 如果输入是普通对象,则直接获取并返回其类型
    const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in);
    return o->type;
    #endif
}

// 获取对象类型的字符串表示
const char *mp_obj_get_type_str(mp_const_obj_t o_in) {
   
    return qstr_str(mp_obj_get_type(o_in)->name); // 通过对象获取其类型,并返回该类型的名称字符串
}

// 辅助函数,用于打印对象
void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
   
    MP_STACK_CHECK(); // 检查栈是否溢出,以避免递归太深导致的问题
    #ifndef NDEBUG
    if (o_in == MP_OBJ_NULL) {
    // 检查对象是否为空
        mp_print_str(print, "(nil)"); // 如果为空,打印"(nil)"
        return;
    }
    #endif
    const mp_obj_type_t *type = mp_obj_get_type(o_in); // 获取对象的类型
    if (MP_OBJ_TYPE_HAS_SLOT(type, print)) {
    // 检查类型是否有打印槽
        MP_OBJ_TYPE_GET_SLOT(type, print)((mp_print_t *)print, o_in, kind); // 调用类型的打印函数
    } else {
   
        mp_printf(print, "<%q>", type->name); // 如果没有打印槽,打印类型的名称
    }
}

// 打印对象的函数
void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) {
   
    mp_obj_print_helper(MP_PYTHON_PRINTER, o_in, kind); // 使用Python打印机和指定的打印类型来打印对象
}

// 辅助函数,用于打印异常和回溯信息
void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc) {
   
    if (mp_obj_is_exception_instance(exc)) {
    // 检查输入是否为异常实例
        size_t n, *values; // 用于存储回溯信息的变量和指针
        mp_obj_exception_get_traceback(exc, &n, &values); // 获取异常的回溯信息
        if (n > 0) {
    // 如果回溯信息不为空
            assert(n % 3 == 0); // 断言回溯信息的数量是3的倍数
            mp_print_str(print, "Traceback (most recent call last):\n"); // 打印回溯信息的标题
            for (int i = n - 3; i >= 0; i -= 3) {
    // 遍历回溯信息
                #if MICROPY_ENABLE_SOURCE_LINE
                mp_printf(print, "  File \"%q\", line %d", values[i], (int)values[i + 1]); // 打印文件名和行号
                #else
                mp_printf(print, "  File \"%q\"", values[i]); // 如果没有启用源代码行支持,只打印文件名
                #endif
                // 打印块名称,如果未知则为NULL
                qstr block = values[i + 2];
                if (block == MP_QSTRnull) {
   
                    mp_print_str(print, "\n"); // 如果块名称为NULL,打印换行符
                } else {
   
                    mp_printf(print, ", in %q\n", block); // 否则打印块名称
                }
            }
        }
    }
    mp_obj_print_helper(print, exc, PRINT_EXC); // 打印异常对象本身
    mp_print_str(print, "\n"); // 打印换行符
}

// 判断对象是否为真值的函数
bool mp_obj_is_true(mp_obj_t arg) {
   
    if (arg == mp_const_false) {
    // 如果对象是False对象
        return 0; // 返回假
    } else if (arg == mp_const_true) {
    // 如果对象是True对象
        return 1; // 返回真
    } else if (arg == mp_const_none) {
    // 如果对象是None
        return 0; // 返回假
    } else if (mp_obj_is_small_int(arg)) {
    // 如果对象是小整数
        if (arg == MP_OBJ_NEW_SMALL_INT(0)) {
    // 如果小整数的值为0
            return 0; // 返回假
        } else {
   
            return 1; // 否则返回真
        }
    } else {
   
        const mp_obj_type_t *type = mp_obj_get_type(arg); // 获取对象的类型
        if (MP_OBJ_TYPE_HAS_SLOT(type, unary_op)) {
    // 检查类型是否有一元操作槽
            mp_obj_t result = MP_OBJ_TYPE_GET_SLOT(type, unary_op)(MP_UNARY_OP_BOOL, arg); // 调用一元操作函数来判断真值
            if (result != MP_OBJ_NULL) {
    // 如果结果不为空
                return result == mp_const_true; // 如果结果为True对象,返回真,否则返回假
            }
        }

        mp_obj_t len = mp_obj_len_maybe(arg); // 尝试获取对象的长度
        if (len != MP_OBJ_NULL) {
    // 如果对象有长度属性
            // 如果长度不为0,则对象为真,否则为假
            return len != MP_OBJ_NEW_SMALL_INT(0);
        } else {
   
            // 任何其他对象都被视为真值,根据Python语义
            return 1;
        }
    }
}

// 判断对象是否可调用的函数
bool mp_obj_is_callable(mp_obj_t o_in) {
   
    const mp_call_fun_t call = MP_OBJ_TYPE_GET_SLOT_OR_NULL(mp_obj_get_type(o_in), call); // 获取调用槽函数
    if (call != mp_obj_instance_call) {
    // 如果调用槽函数不为默认的实例调用函数
        return call != NULL; // 如果调用槽函数不为空,则对象是可调用的
    }
    return mp_obj_instance_is_callable(o_in); // 否则使用默认的实例调用检查函数来判断
}

// 比较两个对象是否相等或不等的函数
mp_obj_t mp_obj_equal_not_equal(mp_binary_op_t op, mp_obj_t o1, mp_obj_t o2) {
   
    mp_obj_t local_true = (op == MP_BINARY_OP_NOT_EQUAL) ? mp_const_false : mp_const_true; // 根据操作类型选择返回值
    mp_obj_t local_false = (op == MP_BINARY_OP_NOT_EQUAL) ? mp_const_true : mp_const_false; // 根据操作类型选择返回值
    int pass_number = 0; // 用于控制比较的遍历次数

    // 针对常见情况的快速路径
    if (o1 == o2 && (mp_obj_is_small_int(o1) || !(mp_obj_get_type(o1)->flags & MP_TYPE_FLAG_EQ_NOT_REFLEXIVE))) {
   
        return local_true; // 如果两个对象相同,并且是小整数或者类型不支持反射比较,则返回真
    }

    // 针对字符串的快速路径
    if (mp_obj_is_str(o1)) {
    // 如果第一个对象是字符串
        if (mp_obj_is_str(o2)) {
    // 如果第二个对象也是字符串
            // 两个字符串对象,使用特殊的字符串比较函数
            return mp_obj_str_equal(o1, o2) ? local_true : local_false;
        #if MICROPY_PY_STR_BYTES_CMP_WARN
        } else if (mp_obj_is_type(o2, &mp_type_bytes)) {
    // 如果第二个对象是字节类型
            // 打印警告信息,因为比较字符串和字节类型可能会导致问题
            mp_warning(MP_WARN_CAT(BytesWarning), "Comparison between bytes and str");
            return local_false; // 返回假
        #endif
        } else {
   
            goto skip_one_pass; // 跳过一个比较遍历
        }
    #if MICROPY_PY_STR_BYTES_CMP_WARN
    } else if (mp_obj_is_str(o2) && mp_obj_is_type(o1, &mp_type_bytes)) 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

openwin_top

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

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

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

打赏作者

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

抵扣说明:

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

余额充值