这是一篇关于piccolo
(一种用纯 Rust 编写的 Lua 解释器)的博客文章,主要内容总结如下:
piccolo
介绍:piccolo
是用纯 Rust 编写的 Lua 语言解释器,注重安全沙箱和弹性,使用gc-arena
进行垃圾回收,可在交互式 REPL 中尝试。作者认为 REPL 很神奇,能让程序更像有生命的东西,与用户更亲近。- 历史:2019 年作者开始写
piccolo
,当时注意到没人能在主要用安全 Rust 实现的情况下,为某些语言创建有竞争力的虚拟机,尤其是垃圾回收问题。piccolo
最初设计类似 PUC-Rio 的 Lua,带有类似的垃圾收集器,但要主要用于沙箱化不受信任的脚本,且用大部分安全的 Rust 实现。最初因遇到很多问题放弃,后因 Ruffle 使用gc-arena
并解决问题而重新开始,但其仍受gc-arena
“Mutation XOR Collection”设计的限制。 - “Stackless”解释器设计:
piccolo
的“stackless”设计是其最大亮点之一,类似其他“stackless”解释器,如 Stackless Python,Lua 运行时不依赖 Rust 函数调用栈,执行可随时暂停,核心设计与 Async Rust 相似,所有长时间运行的操作都可重新表示为需轮询完成的对象。 Stackless 的好处:
- 取消(Cancellation):
piccolo
的轮询执行风格使代码可随时取消,如在 REPL 中运行永不返回的 Lua 代码,可通过点击中断按钮停止,这与 PUC-Rio Lua 的lua_sethook
功能类似,但piccolo
的结构使其更自然,无需提供lua_hook
等效功能。 - 抢先式并发(Pre-emptive Concurrency):Lua 的协程提供协作式多任务,但
piccolo
可通过多个独立的piccolo::Executor
“tasklets”和复用piccolo::Executor::step
调用来实现抢先式多任务,让 Lua 代码像 Rust“任务”一样并发运行,且能保证piccolo::Executor::step
在有界时间内返回,即使 Lua 代码不合作。 - 燃料、节奏和自定义调度(Fuel, Pacing, and Custom Scheduling):
piccolo
中的Fuel
参数用于控制Executor::step
的执行时间,回调可消耗或中断燃料,这使能让 Lua 任务并发运行,并可根据需要调整任务的时间分配,如在游戏引擎中为脚本分配燃料,还可自定义调度以适应不同情况,如在热循环中使print
回调立即返回。 - “对称”协程和
coroutine.yieldto
:Lua 通常有“不对称”协程,只能向调用者 yield,而“对称”协程可向任何其他协程 yield。piccolo
通过其Executor
设计可轻松提供coroutine.yieldto
函数,实现全对称协程,其实现原理与piccolo
的栈无关设计相关,coroutine.yieldto
的实现将控制流重新表示为Executor
的结构,与之前对代码的转换类似。
- 取消(Cancellation):
- “大谎言”:实际上 PUC-Rio Lua 已能实现
piccolo
约 70%的功能,piccolo
的设计是 PUC-Rio Lua 工作方式的自然结论。通过在 PUC-Rio Lua 中使用lua_Hook
函数插入coroutine.yield
可实现简单的任务系统,但存在一些限制,如在 C 回调中调用lua_yield
受限,要使 stdlib 中的所有函数都可挂起需要大量工作,包括重新实现coroutine
库等。 - Rust 协程、Lua 协程和 Snarfing:将 PUC-Rio Lua 转换为类似
piccolo
的系统很困难,piccolo
中的Sequence
trait 与Future
trait 相似,其最初设计意图是让 Lua 从 Rust 中“snarf”协程,即利用 Rust 协程实现piccolo
,但目前无法让 Rust 协程实现gc_arena::Collect
,导致使用gc-arena
和piccolo
很痛苦,需要手动进行转换。 - 展望:作者认为 Rust 的核心思想是作为其他语言的“最后一站”,适合用于不同系统的集成,但不适合所有场景。Lua 能轻松拥有多个解释器副本的特点与系统编程的理念相契合,作者希望打造一个能在 Rust 中像 PUC-Rio 在 C 中一样适配任何地方的 Lua 版本,认为栈无关解释器更适合此目标,同时提到协程是系统编程中应有的抽象,Rust 若能让协程实现
Collect
,将带来有趣的新能力。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。