2 个版本
0.1.1 | 2023 年 9 月 14 日 |
---|---|
0.1.0 | 2023 年 9 月 9 日 |
#554 in 编程语言
305KB
7K SLoC
Silt-Lua,一个 100% 用 Rust 编写的 Lua 超集解释器
该项目最初是为了解决当前 Rust 环境中缺乏 100% 用 Rust 编写的完整 Lua 解释器解决方案的问题。这可能不再一定正确。即使如此,当时现有的实现仍然缺少满足我闭源项目 Petrichor64 要求的关键功能和优化,所以我们就来到了这里。
库的核心重点是具有少量开销和与标准 Lua 相对速度的比较的基本解释器。目标是完美构建 wasm32-unknown-unknown 目标。无需 Emscripten!UserData 将镜像 mlua 和 rlua crate 使用的特性,以允许轻松替换。
次要目标是 CLI、LSP 以及尽可能多的标准库兼容性。还关注安全性,因为虚拟机中存在大量不安全代码。将来,虚拟机的安全和不安全版本将隐藏在功能标志之下,假设不安全版本将运行得略快。精确基准将需要确定。
还有添加一些自定义非 Lua 语法,从其他语言中获取语法的糖,例如允许使用 !=
,类型定义,甚至可能还有箭头函数的愿望。这个 Lua 超集将位于功能标志之下,默认情况下是禁用的,因为谁真的想看到我对编程语言的看法?这个超集满足个人需求,但如果显示出兴趣,我愿意接受请求。即使这个超集被启用,它也不会与标准 Lua 冲突。
这个库是从头开始编写的,基于对 Lua 语言和文档的观察。没有参考源代码,所以虚拟机将始终有一些明显的差异,但希望最终会得到解决。这包括字节码,因为 Lua 现在运行在词码上,以与其基于寄存器的虚拟机一起工作。欢迎提交任何特别突出的问题。该项目是一个学习练习,所以我采取了许多天真方法来实现这一目标。
限制
- 作为基于堆栈的虚拟机构建,而不是基于寄存器,这最终将改变。
- 多个返回仍然在开发中
- 目前还没有真正的垃圾回收器,一些对象使用基本的引用计数,但没有复杂的功能。这意味着在VM中可能会因为像链表这样的自引用结构而创建内存泄漏,但简单的脚本和配置加载应该没有问题。当VM实例被丢弃时,“内存泄漏”仍然会减少。
- 栈还没有得到很好的维护。除了目前缺乏完整的保障外,一些值在弹出后可能仍然留在栈上。这些值没有被忘记,可以被覆盖并丢弃。仍然需要进行大量的测试。尽管如此,有一个程序在运行时会占用全部内存。随着安全级别功能的特性标志的添加,这一问题正在被调查。
- 元方法仍然处于开发中
- 表使用哈希表,虽然将索引值与非索引值混合可以正确生成,但使用
#
将给出实际的哈希表长度,而不是lua的“连续长度”。 - 标准库只有用于测试的
print
和clock
函数。现在可以自由地利用VM实例上的register_native_function
来填补任何空白。
WebAssembly
一个简单的wasm模块示例可以通过wasm-pack编译。如果存在,打印调用全局的jprintln函数。一个实时示例可以在 MakeAvoy.com 上查看。
可选添加(特性标志)
请注意,这些可能会引起争议,LSP会将它们标记为错误。
"bang"
如果迫不得已要使用它们,例如像我一样,可以使用 ! 用于非或或非等于(~=)。它们不替换 not 或 ~=,只是作为内置别名"under-number"
数字可以包含下划线,这些下划线是用于可读性的忽略字符,直接从 rust 借用"short-declare"
从 Go 中直接借鉴,你现在可以声明一个局部变量,例如a := 2
"implicit-return"
块和语句将隐式返回栈上的最后一个值,除非以;
结尾文件顶部的标志如 --!local 强制隐式声明分配到当前作用域,而不是全局级别。您仍然可以通过关键字“global”在任何地方声明全局变量,类似于 python 风格支持匿名箭头函数(C#风格)func_name =param -> param+1
,除了这一点,箭头函数还有隐式返回。栈上的最后一个值总是返回。没有return
关键字的常规函数将返回 nil,就像之前一样。增加器如+=
-=
*=
/=
示例
let source_in = r#"
do
local d=5
function sum()
local a=1
local b=2
local c=3
return a+b+c+d+8
end
return sum()
end
"#;
let mut vm = Lua::new();
vm.load_standard_library();
match vm.run(source_in) {
Ok(value) => {
println!(">> {}", value);
assert_eq!(value, Value:Integer(19));
}
Err(e) => {
e.iter().for_each(|e| println!("!!Err: {}", e));
}
}
依赖关系
~2–3MB
~49K SLoC