Skip to main content

pikapython

PikaPython 应用与 C 模块二次开发指南;开发 parser、VM、runtime 或内核时不使用本 skill。

Quellinformationen

Repository
pikasTech/PikaPython
Letzte Quellaktivität
20. Juli 2026 um 15:02
Erkannte Sprache von SKILL.md
Chinesisch
Sterne
1.759
Forks
171

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
pikapython
description
PikaPython 应用与 C 模块二次开发指南;开发 parser、VM、runtime 或内核时不使用本 skill。
你是一个“Python -> PikaPython C 模块”转换与执行代理。 ## 适用范围 - 本 skill 只服务 PikaPython 用户二次开发: - 编写应用脚本和兼容 PikaPython 子集的 Python 代码; - 开发 `.pyi` 接口与 C 扩展模块; - 为用户模块编写功能测试和 Python/C 实现性能对比; - 调试用户模块的类型、对象生命周期和 API 使用问题。 - 本 skill 不负责 PikaPython 自身开发: - parser、VM、runtime 和核心库修改; - Linux GTest、内核 benchmark、热点分析和 RAM/Flash A/B; - 内核错误合同、可选依赖隔离和版本发布验证。 - PikaPython 自身开发统一在私有 `pikasTech/pika_workspace` 执行,并以 `SKILL.md` 与 `docs/reference/kernel-development.md` 为权威入口。 ## 1 角色与总体目标 给定一段 Python 功能代码(函数 / 类),需自动:生成 PikaPython C 模块 -> 生成测试脚本 -> 构建与运行 -> 提取结果 / 处理错误。 > 重要提醒:PikaPython环境仅支持Python语法子集,标准库极度精简,类型系统严格,所有实现需优先兼容性与健壮性,详见后续章节。 ## 2 执行阶段 ### 2.1 模块生成 在 `file_create/<session_path>/<module_name>` 下生成: 1. 接口:`<module_name>.pyi`。在 `.pyi` 文件中,方法体可以使用 `pass` 或 `...`,两者等效。 2. 实现:一个或多个 `<module_name>_<ClassName>.c` 3. C 函数命名:`<module_name>_<ClassName>_<methodName>` 4. 字符串返回使用:`obj_cacheStr(self, buf)` ### 2.2 测试脚本生成(功能优先,性能后置) 重要提示:在编写 py_... 基线函数前,请务必回顾 6.1 和 6.1.2 节的限制与原则。一个不符合 PikaPython 语法子集的基线核心思想:当简洁性与兼容性冲突时,无条件选择兼容性。一个能在 PikaPython 中正确运行的"笨拙"基线函数,远胜于一个在标准 Python 中高效但无法运行的"优雅"函数。 ### 2.3 构建与运行 执行命令:`python run_pika.py --module <module_name> --module-dir file_create/<session_path> file_create/<session_path>/test_example.py` 常见误区: 误以为 `run_pika.py` 在 `pikapython-linux` 目录下。实际上它在项目根目录,完全不需要用任何的 `cd` 命令切换目录。 错误示例:`cd ./pikapython-linux && python run_pika.py --module <module_name> --module-dir ../file_create/<session_path> ../file_create/<session_path>/test_example.py` 原因: `run_pika.py` 不在 `pikapython-linux` 目录下所以会出错。 ### 2.4 结果提取 从最新 `logs/run/<timestamp>/run.log` 中提取:`[EXAMPLE]`、`[PERF]`、`[EXAMPLE][SELFTEST]` 行。 ### 2.5 错误处理 构建失败:读取 `compile.log` 末 40 行,输出 `[BUILD_FAIL] <摘要>`。 运行失败:读取 `run.log` 末 40 行,输出 `[RUN_FAIL] <摘要>`。 ## 3 命名与实现规范 ### 3.1 文件与路径 允许写入:`file_create/<session_path>/<module_name>/*.pyi`、`file_create/<session_path>/<module_name>/*.c`、`file_create/<session_path>/test_example.py`。无需也禁止对目录执行 `read_file`。 ### 3.2 C 文件/函数命名 文件:`<module_name>_<ClassName>.c` 函数:`<module_name>_<ClassName>_<methodName>` 示例: ``` 模块: math_add 类: MathAdd 方法: add 文件: math_add_MathAdd.c 函数: math_add_MathAdd_add ``` 示例实现: ```c #include "math_add_MathAdd.h" int math_add_MathAdd_add(PikaObj* self, int a, int b){ return a + b; } ``` ### 3.2.1 C 文件头文件规范 * **核心包含**: C 实现文件**必须**包含 `#include "<module_name>_<ClassName>.h"` 以获得 pyi 生成的 binding 的头文件定义,PikaPython 的核心类型与 API 定义。 * **标准库包含**: 如果需要使用标准 C 库函数(如 `strcmp`, `snprintf`),则**必须**包含相应的头文件(如 `#include <string.h>`, `#include <stdio.h>`)。**绝对不应该**包含 PikaPython 项目内部的其他非 `<module_name>_<ClassName>.h` 的头文件。 ### 3.2.2 函数封装规范 * **强制类封装**: 所有 Python 功能,即使用户仅提供独立函数,在生成 C 模块时也**必须**被封装在一个类中。不允许生成直接映射到 C 的顶层函数。 ### 3.3 返回值与字符串 * **浮点返回**: 优先使用 `pika_float` 以避免被解释器截断为 `0.0`。 * **字符串返回**: 当返回函数内的局部变量字符串时,必须使用 `obj_cacheStr()` 进行缓存,以防悬垂引用。 ```c char buf[32]; snprintf(buf, sizeof(buf), "%d", value); return obj_cacheStr(self, buf); ``` * **函数签名陷阱**: C 函数的返回类型必须与接口头文件严格匹配。返回 `Arg*` 而接口期望 `PikaObj*` 会导致 "conflicting types" 编译错误。返回对象时使用 `PikaObj*`(返回 `NULL` 表示 None),返回混合类型时使用 `Arg*`(用 `arg_newObj()` 包装对象)。 * **Arg* 返回值处理 (重要先验知识)**: * **核心陷阱**: 不能直接引用或复制现有的 `Arg*` 对象返回。`arg_incRef()` 和 `arg_newRef()` 等API可能不存在或参数类型不匹配。 * **正确模式**: 根据数据类型使用对应的构造函数创建新的 `Arg*` 对象: ```c // 错误:尝试引用现有对象 return arg_incRef(existing_arg); // 函数不存在 return arg_newRef(existing_arg); // 参数类型不匹配 // 正确:创建新的类型特定对象 if (arg_getType(result_arg) == ARG_TYPE_INT) { return arg_newInt(arg_getInt(result_arg)); } else if (arg_getType(result_arg) == ARG_TYPE_FLOAT) { return arg_newFloat(arg_getFloat(result_arg)); } else if (arg_getType(result_arg) == ARG_TYPE_STRING) { return arg_newStr(arg_getStr(result_arg)); } ``` * **常见误区**: 认为可以像标准C一样直接返回指针或引用对象。在PikaPython中,必须通过API构造函数创建运行时可识别的对象。 * **重要提醒**: 处理混合数据类型时,务必先通过 `arg_getType()` 检查类型,再使用对应的 `arg_get*()` 函数获取值,否则可能导致类型不匹配错误。 * **bytes 返回**: `bytes` 作为返回值时,C 函数应返回 `Arg*` 类型。必须使用 `arg_newBytes(bytes_ptr, len)` 来创建返回值。 ```c // 示例: 返回一个 bytes 对象 uint8_t data[] = {0x01, 0x02, 0x03}; return arg_newBytes(data, sizeof(data)); ``` ### 3.4 `None` 值与复杂返回值处理(重要) #### 3.4.1 `None` 值的正确处理 API 处理 `None` 是常见的失败点。必须使用以下标准 API: * **返回 `None`**: 使用 `arg_newNone()`。此函数返回一个 `Arg*` 类型的 `None` 值。 ```c // 正确示例: 当列表为空时返回 None if (pikaList_getSize(nums) == 0) { return arg_newNone(); } ``` * **检查 `None`**: 使用 `arg_getType(arg) == ARG_TYPE_NONE`。 ```c // 正确示例: 检查返回值是否为 None Arg* result = some_function(self, nums); if (arg_getType(result) == ARG_TYPE_NONE) { // 处理 None 的情况 } ``` * **常见误区**: * **禁止使用 `arg_setNull(NULL)`**: 这是一个过时且类型不安全的宏,会引发编译警告或错误。 * **禁止使用 `arg_isNull(...)`**: 这个函数不存在,会导致链接错误。 #### 3.4.2 处理“对象或 None”的返回值 当一个 C 函数可能返回一个 PikaPython 对象(如 `list`, `tuple`, `dict`)或者 `None` 时,该函数的返回类型**必须**声明为 `Arg*`。 * **函数签名**: ```c // 错误: PikaObj* 无法直接承载 None PikaObj* my_function(PikaObj* self, PikaObj* nums); // 正确: Arg* 可以同时代表对象和 None Arg* my_function(PikaObj* self, PikaObj* nums); ``` * **返回对象 (重要修正)**: 当返回一个 PikaPython 对象(如 `PikaTuple*`, `PikaList*`)时,**必须**使用 `arg_newObj()` 将其包装成 `Arg*`。一律使用 `arg_newObj` 以减少显式类型参数与误用风险。 * **推荐用法**: `arg_newObj((PikaObj*)some_obj)` * **常见误区**: 不要使用 `arg_setPtr()` 试图原地修改;那通常需要已有 `Arg` 实例,且更容易产生生命周期或类型不匹配问题。 ```c // 正确示例: 返回一个元组对象 PikaTuple* tuple = New_PikaTuple(); // ... 填充 tuple ... return arg_newObj((PikaObj*)tuple); ``` * **安全地使用返回值**: 从 `Arg*` 类型的返回值中提取对象指针前,**必须**先检查它是否为 `None`,否则可能导致段错误。 ```c Arg* result_arg = my_function(self, nums); // 1. 必须先检查 None if (arg_getType(result_arg) == ARG_TYPE_NONE) { // ... 处理 None ... return; } // 2. 确认不是 None 后,再安全地获取对象指针 PikaObj* result_obj = arg_getPtr(result_arg); // ... 在此使用 result_obj ... ``` 在 `test_example.py` 中,始终使用 `is None` 来断言 `None` 值。 ```python val_mod = stats.min_max([]) assert val_mod is None, "min_max of empty list should be None" ``` ### 3.5 列表 (List)、元组 (Tuple)、字典 (Dict) 操作指南 #### 3.5.1 **核心陷阱:Python `int` 与 C `float` 的类型不匹配** **警告:这是最常见的失败原因!** 当一个包含整数的 Python 列表(如 `[1, 2, 3]`)被传递到 C 模块时,其元素的类型是 `ARG_TYPE_INT`。如果你直接使用 `arg_getFloat()` 或 `pikaList_getFloat()` 去读取这些值,你会得到 `0.0` 而不是期望的整数值。 **正确的数据提取模式:** 必须先获取通用 `Arg*`,然后检查其类型,最后使用对应的 `get` 函数。 ```c // 正确的、健壮的列表遍历方式 int len = pikaList_getSize((PikaList*)nums); // 注意:参数通常是 PikaObj*,需要强制转换 for (int i = 0; i < len; i++) { Arg* arg = pikaList_get((PikaList*)nums, i); pika_float val = 0.0; // 检查类型并分别处理 if (arg_getType(arg) == ARG_TYPE_INT) { val = (pika_float)arg_getInt(arg); } else if (arg_getType(arg) == ARG_TYPE_FLOAT) { val = arg_getFloat(arg); } // ... 在此处理 val ... } ``` #### 3.5.2 PikaPython 核心对象创建与操作 * **创建空对象**: * `PikaList* my_list = New_PikaList();` * `PikaTuple* my_tuple = New_PikaTuple();` * `PikaDict* my_dict = New_PikaDict();` * **错误用法**: 不要使用 `newNormalObj(New_List)`,这是过时且错误的。 * **列表 (List) 操作**: * 添加元素: `pikaList_append(my_list, arg_newFloat(3.14));` * 获取长度: `int len = pikaList_getSize(my_list);` * 获取元素: `Arg* val_arg = pikaList_get(my_list, i);` (参见 3.5.1 的类型处理) * **列表遍历 (重要先验知识)**: * **推荐模式:使用 `pikaList_forEach` 回调**: 这是遍历列表最健壮、最高效的方法。 * **核心陷阱**: `pikaList_forEach` 的回调函数签名是固定的,必须包含 `itemIndex` 参数。错误的签名会导致编译警告 (`-Wincompatible-pointer-types`) 和潜在的运行时错误。 * **正确签名**: `int32_t callback(PikaObj* self, int itemIndex, Arg* itemEach, void* context)` * **示例**: ```c // 1. 定义一个上下文结构体来持有状态 typedef struct { PikaList* integers; PikaList* strings; } MyContext; // 2. 实现回调函数 (注意 itemIndex 参数) int32_t process_item_callback(PikaObj* self, int itemIndex, Arg* item_arg, void* context) { MyContext* ctx = (MyContext*)context; if (arg_getType(item_arg) == ARG_TYPE_INT) { pikaList_append(ctx->integers, item_arg); } else if (arg_getType(item_arg) == ARG_TYPE_STRING) { pikaList_append(ctx->strings, item_arg); } return 0; // 返回 0 以继续遍历 } // 3. 在主函数中调用 forEach MyContext ctx = { .integers = New_PikaList(), .strings = New_PikaList() }; pikaList_forEach((PikaList*)items, process_item_callback, &ctx); // 遍历结束后, ctx.integers 和 ctx.strings 将包含所需结果 ``` * **元组 (Tuple) 操作**: * 元组在 C 层面通常被当作**不可变列表**处理。 * 创建并填充元组: ```c PikaTuple* tuple = New_PikaTuple(); pikaList_append((PikaList*)tuple, arg_newFloat(val1)); pikaList_append((PikaList*)tuple, arg_newFloat(val2)); return (PikaObj*)tuple; // 返回时转换为 PikaObj* ``` * 读取元组: ```c // 假设 min_max_tuple 是一个 PikaObj* pika_float mn = pikaList_getFloat((PikaList*)min_max_tuple, 0); ``` * **字典 (Dict) 操作**: * 设置键值对: ```c pikaDict_setFloat(my_dict, "mean", 12.3); pikaDict_setInt(my_dict, "count", 5); pikaDict_setStr(my_dict, "status", "ok"); ``` * **核心陷阱:在字典中存储对象(如列表、其他字典)**
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen