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