17个版本 (4个重大更新)
0.8.6 | 2022年5月13日 |
---|---|
0.7.1 | 2022年5月7日 |
0.1.13 |
|
在 编程语言 类别中排名 317
每月下载量 101 次
545KB
13K SLoC
Sphinx
Sphinx 是一种受 Lua 和 Python 启发的动态类型编程语言,完全用 Rust 实现!
Sphinx 还不完整!它处于预 alpha 开发阶段,在它成为完全功能化的语言之前还有很多工作要做。我的计划包括以下内容
- 导入系统
- 一个基本的标准库
- 确定类/对象系统的细节
目标
我的目标是拥有一个轻量级、表达力强的语言。同时,我也希望语言运行时运行得足够快。
此外,这个整个项目最初是为了学习 Rust 而开始的,我确实学到了很多。我也希望有一天它能成为一个实际的、实用的和完整的开发工具,但这还有很长的路要走。
好吧,我该如何运行它?
Sphinx 使用 Rust 的 指针元数据 API,该 API 尚未稳定。因此,为了构建它,您需要 nightly Rust。可能如果您在这里,您对编译器/VM 的内部结构感兴趣(因为语言本身还是相当 WIP),所以您可能已经知道如何设置它,但如果不知道,您可以使用 rustup
获取它。
构建完成后,您可以使用 sphinx
运行 REPL,使用 sphinx-dasm
运行反汇编器。这两个可执行文件都有 --help
来列出命令行选项。还可以查看 sphinx
上的 --debug
选项,该选项允许您逐条指令执行并查看虚拟机的状态。以下是一些您可以运行的示例代码以开始使用
如果您运行REPL,globals()
函数将允许您查看当前可用的内置函数。虽然 help()
函数尚未完全支持,但它已经存在。目前,它只接受函数并打印函数签名。
# Makes a counter using closures
fun make_inc()
var a = 0
fun inc(s = 1)
nonlocal a += s
end
end
# Warning - very slow! This was intended for a stress test.
# You will definitely notice a speedup if compile Sphinx in release mode.
fun fib(n)
if n < 2 then
return n
end
fib(n - 2) + fib(n - 1)
end
# Some fun with tuple assignment
# declare "c" and "d" as mutable, the rest as immutable, and capture any excess in a tuple
let a, b, (var c, d), e, rest... = 1, 2, (3, 4), 5, 6, 7
c += (d *= 2)
assert a, b, c, d, e == (1, 2, 11, 8, 5)
assert rest == (6, 7)
您还可以查看 tests
文件夹中的某些测试脚本。
目前,sphinx
会从内存中编译代码并执行它。我计划添加对二进制字节码输入/输出的支持,但目前的文件格式尚未确定。
我喜欢实现的一些事情
我在一个基于 MetaObject
特性的内部类型系统中构建了一个类型系统,这使得指定语言中每个核心原始类型支持的行为变得容易。多亏了Rust的枚举类型(和一些宏),这在不使用vtable的情况下实现,使用基于枚举区分符的运行时调度。
字符串数据的不同表示形式。尽可能在栈上内联短字符串(受flexstr的启发)。所有用作标识符的字符串都被内部化。只有长度超过40字节的字符串才使用GC分配。字节码编译器将局部变量名称转换为值栈的索引,因此引用局部变量时根本不使用字符串。
Sphinx语言使用一个简单的受rust-gc
启发的Mark-Trace GC。运行时 本身不使用任何GC。由于我们只GC脚本数据,因此避免了编写通用Rust代码GC时涉及到的许多挑战(例如,rust-gc
需要处理的)。
GC还支持不使用双间接引用动态分配大小类型(即用于GC数据的 Gc<T>
智能指针直接指向DST,而不是Box)。它还使用瘦指针 来引用动态分配,从而将每个 Gc<T>
的大小减少到单个 usize
。GC还支持弱引用!
未来,我希望支持增量GC和可能 代际GC,但当前实现简单且效果不错。
它是编译型语言还是解释型语言?
Sphinx被编译为字节码中间表示形式,并在虚拟机上运行。未来,我希望迁移到JIT实现,但还有许多其他事情要处理。
安全Rust FFI
由于Sphinx主要使用安全Rust实现,因此应该可以提供完全安全的Rust FFI。这将允许宿主Rust应用程序获得嵌入式动态脚本语言的能力。
作为一个长期目标,我希望能利用rlua绑定在Sphinx中提供Lua FFI。
语法高亮支持
目前,Sublime Text用户可以几乎完全实现语法高亮 - 只需将 sphinx.sublime-syntax
复制到您的用户包目录中。如果您使用不同的文本编辑器并希望为Sphinx提供语法高亮,请随时在GitHub上提出请求。使语言工作是我的首要任务,但我不介意查看它。
示例(尚未完全实现)
#{
Block Comment
#{ Nested! }#
}#
print("Hello, world!")
# Semicolons are optional. The syntax has been designed so that the end of a statement can always be inferred.
"One"; "Two"
# Mutable and immutable variables
let immutable = "can't change me"
var mutable = 0
print(mutable += 1) # almost all constructs in Sphinx are expressions
var annotated: Float = 3.14159 # not implemented yet, but someday...
# Tuples
"abc", 123
# Tuple assignment
var first, second = "abc", "def"
second, first = first, second
assert "def", "abc" == first, second
# Objects
{ value = 0xA } # anonymous object
Person { value = 0xC } # classy object
# Functions, including default and variadic arguments
# note: default arguments are re-evaluated with each invocation (unlike Python)
fun echo_default(thing = "default")
print(thing)
end
fun variadic_fun(normal_arg, variadic...)
print(normal_arg )
for variadic_arg in variadic do
print(variadic_arg)
end
end
variadic_fun("red", "blue", "green") # prints "red" then "blue" then "green"
# Note: named arguments are not supported. It may be added in the future.
# You can pass an anonymous object instead.
configure_something({ option1 = true, option2 = false })
# Argument unpacking and wrapping decorators
fun trace(wrapped)
return fun(args...)
print("trace")
wrapped(args...)
end
end
# "@decorator let/var name = value" is syntactic sugar for "let/var name = decorator(value)"
# And "fun name() ... end" is syntatic sugar for "let name = fun() ... end"
# Put that together and we can do:
@trace
fun increment(x)
return x + 1
end
# Classes, Metatables
# WIP/TBD
依赖项
~5–14MB
~146K SLoC