#编程语言 #动态 #动态地 #sphinx #实现 #类型 #动态编程

nightly bin+lib sphinx-lang

用Rust实现的动态语言解释器

17个版本 (4个重大更新)

0.8.6 2022年5月13日
0.7.1 2022年5月7日
0.1.13 2022年3月30日

编程语言 类别中排名 317

Download history 8/week @ 2024-03-29

每月下载量 101

MIT 许可证

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