# PyFly 实现方案 Fly = Python 3.10+ 安全增强超集,用 Go 实现转译器(Fly → Python,类似 TypeScript → JavaScript)。 新增 8 个安全关键字,编译期检查 + 展开删除,输出纯净 Python。 ## 语言定位 - Fly 源码是 Python 3.10+ 超集,转译后为合法 Python,无残留语法 - 8 个关键字:`safe` `only` `lock` `mask` `cage` `guard` `seal` `trace` - 编译期报错输出到终端,退出码 1;`fly check` 仅检查不输出代码 ## 编译管线 ``` .fly → Lexer → Parser(AST) → 语义分析(checker) → 编译期报错 → 代码生成 → .py │ │ └── lock/guard/mask/safe 拦截 ──┴── only/seal/trace/cage 展开注入 ``` ## 项目结构(Go 标准库,零第三方依赖) ``` flylang/ ├── go.mod ├── cmd/fly/main.go # CLI: fly build [-o out.py] / fly check / fly run ├── internal/ │ ├── lexer/ # Python 3.10+ 子集 + 8 关键字 token │ ├── ast/ # 节点定义 + 位置信息(报错行列号) │ ├── parser/ # 递归下降;only:/cage():/seal class/mask x 等新语法 │ ├── checker/ │ │ ├── symbol.go # 符号表、作用域、lock 只读拦截、import 收集 │ │ ├── taint.go # 赋值 def-use 链:safe(源→危险汇点) mask(敏感→输出上下文) │ │ ├── whitelist.go # only 块内名字 vs 白名单 │ │ └── guard.go # guard 条件合法性验证 │ ├── gen/ │ │ ├── python.go # 缩进化 Python 代码发射 │ │ └── inject.go # seal/trace/cage/only 运行时注入 │ ├── version/ # Version/Commit/Repo(ldflags -X 注入) │ ├── update/ # 自更新:GitHub Releases API + socks5/http 代理(手写 SOCKS5) │ └── runtime/fly_runtime.py # go:embed;GuardError/ResourceExhaustedError、白名单代理、冻结容器 ├── tools/icon/ # 图标生成器(输出 assets/icon.png) ├── assets/ # logo.svg + icon.png ├── .github/workflows/release.yml # 打 v* tag → deb/pkg/dmg/zip/SFX + GitHub Release ├── editor/vscode-fly/ # VSCode 插件(TypeScript) │ ├── package.json # contributes: languages/grammar/commands/configuration │ ├── syntaxes/fly.tmLanguage.json # TextMate 语法高亮(Python 子集 + 8 关键字) │ ├── src/extension.ts # 激活逻辑 │ ├── src/diagnostics.ts # 调 `fly check` 解析报错 → Problem Panel │ └── src/commands.ts # build/run/update 命令 └── testdata/ # .fly 正反例(# fly:error 标记期望编译错误) ``` ## VSCode 插件 轻量方案,不引入 LSP(编辑器体验先行,LSP 留待后续): - **语法高亮**:TextMate grammar(`syntaxes/fly.tmLanguage.json`),基于 Python 语法注入 8 个关键字样式(`safe`/`mask`/`lock`/`guard` 与 `only`/`cage`/`seal`/`trace` 可区分色) - **编译期诊断**:`diagnostics.ts` 保存时或手动触发,后台执行 `fly check `,解析 `error: file:line:col: msg` 输出到 Problems 面板 - **命令**:`Fly: Build to Python`(转译当前文件并显示/保存 .py)、`Fly: Check`(手动检查) - **配置**:`fly.path`(fly 可执行文件路径,默认 `fly`)、`fly.checkOnSave`(默认 true) - **未装 fly 时的降级**:提示安装并给出构建命令 开发与打包:`npm install` → `npm run compile` → F5 调试(Extension Development Host);打包用 `vsce package`。 ## 关键字落地分工 | 关键字 | 编译期动作 | 运行时残留 | | :--- | :--- | :--- | | `safe` | 污点追踪:I/O 源(request/input)→ `safe` 声明点;未净化变量传入 eval/exec/os.system/SQL 拼接等汇点 → 报错 | 无 | | `only` | 白名单校验:块内名字/import 与白名单比对,出现 os/subprocess 等 → 报错 | 注入 `__builtins__` 白名单代理,重写块内 import | | `lock` | 符号表只读标记:拒绝再赋值、AugAssign、setattr、`globals()['X']` 反射读取 | 生成冻结常量容器 | | `mask` | 反向追踪:mask 变量出现在 print/logging/f-string 输出上下文 → 报错 | 无 | | `cage` | 解析 max_time/max_memory 参数,按块包装 | 生成装饰器:`signal.SIGALRM` 计时 + `resource.setrlimit` 限内存,抛 `TimeoutError`/`ResourceExhaustedError` | | `guard` | 验证约束为布尔表达式、变量与断言匹配 | 展开为 `if not (...): raise GuardError(...)` | | `seal` | 标记类、收集类属性 | 类体内注入 `__setattr__`/`__delattr__`,非初始化阶段增删改一律抛错 | | `trace` | 解析 level/args/ret 参数 | 函数入口/出口插入 logging 调用,含参数与返回值 | ## 报错格式 ``` error: .fly:12:5: lock 变量 SECRET_KEY 不可再赋值 ``` 行列为 AST 节点位置。 ## 测试策略 - 单元:lexer/parser 各语法节点 - checker:testdata 表驱动反例测试(`# fly:error` 注释标记期望错误,编译必须报错) - 集成:golden 测试对比转译输出 - 行为:生成的 .py 用 Python 3.10 实跑验证 cage/seal/trace 运行时行为 ## 发布与自更新 - 打 `v*` tag → `.github/workflows/release.yml`:Linux(deb/tar.gz,amd64+arm64)、macOS(pkg/dmg universal)、Windows(zip + 7z SFX installer),`gh release create` 自动发布 - `fly update`:查 GitHub Releases latest → 按 `fly--.tar.gz|.zip` 匹配下载 → 校验 → 原子替换自身;`--check` 有新版本退出码 2;`--proxy` 支持 `http(s)://` 与 `socks5://[user:pass@]host:port`(手写 SOCKS5,零依赖) - 版本注入:`-ldflags "-X flylang/internal/version.Version=... -X ...Commit=... -X ...Repo=29anan29/Fly-lang"`,未注入时显示 `dev` ## 开发过程(P0 → P6) 每阶段退出标准(DoD):`go vet ./...` 与 `go test ./...` 全绿;新功能有正反例测试;生成的 .py 用 Python 3.10 实跑通过。 ### P0 基础设施(CLI + Lexer + Parser + AST) **目标**:端到端骨架跑通——任意不含关键字的子集 .fly 可无损转译并执行。 任务: 1. `go.mod` + 目录骨架(cmd/internal/testdata) 2. `internal/ast/pos.go`:Position + Diagnostic 错误类型(`error: ::: `) 3. `internal/lexer/`:token 定义(Python 3.10+ 子集 + 8 关键字)、缩进栈、f-string、字符串转义、数字/注释 4. `internal/ast/`:节点全集(模块/函数/类/if/for/while/import/赋值/表达式/调用/f-string/异常) 5. `internal/parser/`:递归下降,parse 出模块树;解析错误也带行列号 6. `internal/gen/`:最小 AST→Python 编码器(只做格式重排,不注入) 7. `cmd/fly/main.go`:`build`(默认写同目录 .py、`-o` 指定)/ `check`(只检查退出码 1)/ `run`(临时文件跑 python3) 8. testdata 首批正例 + golden 测试框架(输出快照对比) 验收:`hello.fly` 转译后 `python3` 实跑输出一致;错误样例报错格式正确。 ### P1 符号表 + lock + guard(纯编译期先行) **目标**:编译器第一次"拦截"能力——`lock` 冻结常量、`guard` 展开断言,零运行时残留。 任务: 1. `checker/symbol.go`:作用域符号表(模块/函数/类)、名字收集、import 表 2. `lock` 拦截:对 lock 名的 Assign/AugAssign/`setattr`/`globals()['X']`/`vars()['X']` 一律报错 3. `guard` 验证:变量必须已定义、条件为布尔表达式;gen 展开为 `if not (...): raise GuardError(...)` 4. checker 错误聚合(一次报多个错误,最多 N 条上限) 5. testdata 反例:lock 篡改、guard 类型不匹配等,用 `# fly:error` 标记 验收:`lock SECRET = "x"` 后任何再赋值/反射读取编译失败;`guard age: int, 0 < age < 150` 展开正确。 ### P2 污点引擎(safe / mask) **目标**:数据流分析落地——`safe`(源→危险汇点)与 `mask`(敏感→输出上下文)双向污点。 任务: 1. `checker/taint.go`:def-use 链(赋值/函数调用参数/返回值/容器元素/属性传播) 2. 源点表:`request.*`、`input`、`os.environ` 等 I/O 源 3. 汇点表:`eval`/`exec`/`os.system`/`subprocess.*`/SQL 字符串拼接 4. `safe x` 声明点语义:声明的污点变量被清洗(`int(x)` 等)后解除污点;未清洗流入汇点→报错 5. `mask x`:变量流入 `print`/`logging.*`/f-string/字符串格式化→报错;允许哈希/比较等非输出上下文 6. 反例测试:`safe uid` 后 `eval(uid)` 报错、`mask password` 后 `print(password)` 报错;正例(清洗后/比较后)不误报 验收:文档示例 1(safe)与 4(mask)的注释行全部编译报错,正文行全部通过。 ### P3 注入型关键字(only / seal / trace)✅ 完成 **目标**:代码生成开始"改写"——白名单块、类冻结、审计日志。 任务: 1. `only (mods):` 块:解析白名单、块内名字/import 比对(os/subprocess/eval 等→报错);gen 重写块内 import + 注入 `__builtins__` 白名单代理 ✅(checker/only.go 黑名单 + gen `_FlyOnly` 代理 + `_fly_patch_builtins` 函数包装) 2. `seal class`:收集类属性;gen 在类体注入 `__setattr__`/`__delattr__`(非 `__init__` 阶段增删改抛错);实例属性赋值(`admin.role = "user"`)编译期可静态识别则直接报错 ✅(checker 静态拦截 + 运行时 `_fly_seal_initializing` 门控) 3. `trace(level=, args=, ret=)`:函数入口/出口插入 logging 调用(参数与返回值)✅(gen 包装函数 + `_fly_trace_impl_` 原函数保留) 4. 反例:only 块内 `os.system` 报错、seal 类实例赋值报错;正例:合法模块调用通过 ✅(testdata/errors/only_seal.fly、testdata/golden/p3.fly) 5. fly_runtime.py 起步:GuardError 等异常类型 ✅(internal/runtime/fly_runtime.py go:embed,按 `# fly:section:` 标记提取注入 guard/only/trace 三节) 验收:文档示例 2/7/8 的注释行全部报错;生成的 .py 结构正确且 Python 3.10 语法合法。✅ ### P4 资源约束(cage + runtime 库)✅ 完成 **目标**:运行时防御闭环,`cage` 限制时间/内存并抛规范异常。 任务: 1. `cage(max_time=, max_memory=):` 解析参数("5s"/"100MB" 单位换算)✅(parser 解析 max_time: ms/s/m/h、max_memory: B/KB/MB/GB(+iB),运行前换算为秒/字节) 2. gen 包装:装饰器生成(`signal.SIGALRM` 超时 + `resource.setrlimit` 限内存 + 清理恢复)✅(`@_fly_cage(...)` 装饰器注入 cage 块内函数;setitimer 计时 + RLIMIT_AS 软限压降,finally 恢复) 3. fly_runtime.py 完善:`TimeoutError`/`ResourceExhaustedError` 包装、资源恢复逻辑 ✅(cage 节:`_fly_cage` 装饰器 + `ResourceExhaustedError` + `_fly_timeout_handler`;MemoryError→ResourceExhaustedError 转换;只降软限避免无权限硬限恢复失败) 4. 行为测试:`while True` 超时抛错、大数组分配抛 ResourceExhaustedError(python3 实跑)✅(testdata/p4_cage.fly 双场景触发 + 嵌套 cage/重复调用/正常快路径验证) 验收:文档示例 5 转译后实跑,超时与超内存两种场景均触发并抛对应异常。✅ ### P5 VSCode 插件(已升级为 LSP 版) **目标**:编辑器体验——高亮 + LSP 编译期诊断。 任务: 1. `internal/lsp`:零依赖 JSON-RPC over stdio 服务器(Content-Length 帧、请求/通知分发、错误聚合) 2. 能力:initialize/initialized/shutdown/exit、didOpen/didChange(full)/didSave/didClose、publishDiagnostics(`compile.CheckSource` 内存编译,120ms 防抖)、hover(8 关键字文档 + 所在行)、自定义 `fly/forceCheck` 3. `cmd/fly` 新增 `lsp` 子命令(stdio) 4. `editor/vscode-fly/` 插件:vscode-languageclient v10 连接 `fly lsp`,TextMate 高亮保留,命令(Build/Run/Update/ForceCheck) 5. 配置 `fly.path`/`fly.proxy`;`fly.checkOnSave` 移除(LSP 常驻) 6. 验证:lsp 单测(管道模拟完整会话)+ `vsce package` + `code --install-extension` 验收:F5 调试下 .fly 文件实时诊断(与 `fly check` 同管线);hover 出关键字说明;`fly lsp` 冒烟会话(initialize/didOpen/shutdown/exit)通过。 ### P5.5 发布生态(CI 打包 + 自更新 + 图标) **目标**:一键发布多平台安装包,`fly update` 原地升级。 任务: 1. `tools/icon/` 图标生成器(多边形光栅化 → assets/icon.png) 2. `internal/version`:ldflags 注入版本/提交/仓库 3. `internal/update`:GitHub API 查版本、AssetFor 按平台匹配、tar.gz/zip 解包原子替换、socks5 代理(含认证)手写实现 + 表驱动测试 4. `cmd/fly` 新增 `version`/`update` 子命令(--check 退出码 2 / --force / --proxy) 5. `.github/workflows/release.yml`:deb/tar.gz/pkg/dmg/zip/SFX 五类产物 + Release 发布 6. VSCode 插件补 `Fly: Check for Updates`(复用 `--check`/`--force` + `fly.proxy` 配置) 验收:本地 dpkg-deb 冒烟打包通过;`go test ./...` 全绿。 ### P6 打磨与收尾 ✅ 完成 任务: 1. golden 测试全量覆盖 + 错误消息快照测试 ✅(TestErrorSnapshots:24 个 errors 反例的 `.err` 快照逐行比对,与 LSP 同一 FormatError 管线) 2. 边界用例:嵌套作用域、闭包、递归、f-string 内 mask 变量、only 嵌套 ✅(golden/edge.fly 正例防误报:shadowing/闭包/递归/嵌套 only/safe 清洗;errors/edge_nesting.fly 反例:闭包内 mask 泄露、嵌套 only 内 os、深层嵌套 mask) 3. 文档:README(安装/用法/8 关键字速查)、报错清单整理 ✅(docs/报错清单.md:全部错误消息 + 运行时异常表;README 链接) 4. `go vet`、gofmt 全绿;`vsce package` 产出 .vsix ✅(插件 v0.3.0,本地打包 12.56 KB 通过) 验收:CI 式一键命令 `go test ./... && go vet ./...` 全绿;对方案.md 全部 8 个示例做最终回归。✅(testdata/acceptance/all8_ok.fly 正例全部通过并 python3 实跑;errors/all8_err.fly 反例 9 条错误全部命中) 里程碑:P0-P6 全部完成,发布 v0.3.0(正式版 release 渠道)。 ### P7 编译期完备检查(check 通过 = 无原生运行时崩溃)✅ 完成 编辑器 check 优化 + 编译前检查强化,两阶段保证: 1. **静态检查扩展**(checker/runtime.go): - 未定义名称:模块级顺序敏感(引用须先赋值/import),函数体宽松(参数+局部+外层+内置) - 本地函数参数个数:不足/过多/未知关键字/重复传值 - 常量除零:`/`、`//`、`%` 字面量 0 - 重复定义:同作用域函数/类/import 撞名、参数重复 - 字面量类型操作:二元运算/一元/下标/in 的类型兼容表 2. **运行时兜底**(gen 注入 `_fly_*` 护栏 + FlyRuntimeError): - `_fly_binop`(含除零)/`_fly_unary`/`_fly_get`/`_fly_set`/`_fly_attr`/`_fly_setattr`/`_fly_cmp`/`_fly_iter`/`_fly_cast`(int/float) - 动态错误统一 `FlyRuntimeError: src:行:列: 描述`,不再裸抛 Python 异常 - only 代理放行 `_fly_` 前缀 + FlyRuntimeError/GuardError 3. 编辑器同步:LSP 与 `fly check` 同一 CheckSource 管线,新检查自动生效;`fly build` 编译前检查本就同管线 验收:新增 undefined_name/dup_def/literal_type/arg_count 反例 + 快照;golden 全量(含转译注入回归);TestRuntimeCatch 实跑验证 5 类动态错误全部转 FlyRuntimeError;`go test ./... && go vet ./...` 全绿。 ## 里程碑(与阶段对应) P0 基础设施 ✅ → P1 lock/guard ✅ → P2 safe/mask ✅ → P3 only/seal/trace → P4 cage+runtime → P5 VSCode 插件 → P5.5 发布生态 → P6 打磨 → P7 编译期完备检查 ### 当前进度 - P1(已完成):`internal/checker/`(symbol.go 作用域符号表 + lock.go 冻结常量拦截 + guard.go 条件验证)、parser 支持 `lock`/`guard` 语法(含 `guard x > 0` 纯条件形式)、gen 展开 guard 为 `if not (...): raise GuardError(...)` 并注入 `GuardError` 类、错误聚合上限 20 条、LSP 诊断同步;golden(lock/guard)+ 9 个 errors 反例 + checker 单测全绿 - P2(已完成):`checker/taint.go` 污点引擎(顺序数据流:赋值/容器/属性/下标传播、清洗 `int`/`float`/`bool`、函数返回污点、f-string 变量提取);源点(`input()`/`request.*`/`os.environ`);汇点(`eval`/`exec`/`compile`/`os.system`/`subprocess.*`/SQL `execute`;`print`/`logging.*` 输出);`safe`/`mask` 零运行时残留;golden safe_mask + 7 个 errors 反例 + 污点单测全绿;`方案.md` 示例 1/4 验收通过