编程语言的诞生:Slate [第一部分]
[第一部分] 简介
石板!
那么它现在能做什么呢?一种新的语言?为什么?它有什么不同?我能用它吗?
你是怎么做到的?
我发明了一种新的编程语言!(((注意:目前它只能将数字文字相加并导出常量,但它可以运行!!))
[第一部分] 简介
石板!
最近,我一直在开发一种全新的编程语言,它叫做 Slate!我会把它写成一个系列,大致从头到尾记录我开发编译器、标准库,甚至一些 Slate 程序的进度。
Slate 是(第一个?)直接从源代码编译为WebAssembly 的编程语言。是的,这就是我这么久以来一直在问 WASM 的原因 :)。它的语法主要受到 JavaScript ES2015+ 的启发,同时也受到了 Java、Kotlin 等语言的影响。
那么它现在能做什么呢?一种新的语言?为什么?它有什么不同?我能用它吗?
目前,这就是它所做的一切。
/**
* https://github.com/nektro/slate/blob/master/tests/02.grammar/01.operators/001.slate
*/
//
export const expected = 80;
//
export function main(): i32 {
return 48 + 32;
}
怎么办?
您可以导出整型常量文字,并导出一个用于将整型文字相加的函数。就是这样。但slate.js
可以完全解析它,并导出一个执行相同操作的 WASM 模块,尽管目前还只是非常字面化的。
为什么要做?
我真心热爱 JavaScript。这份热爱源于对 Web 平台的广泛热爱,而 JS 正是我们所能拥有的一切。直到现在!WebAssembly 解答了那个老问题:“除了 JavaScript,Web 上还有其他语言吗?”。WASM 则让 JavaScript 可以访问所有语言[1]。因此,一方面出于对 JS 的热爱,另一方面出于创建自己的语言的渴望,为了尝试实现我从未见过的功能,我开始着手通过 WASM 创建一种专门用于 Web 的语言。
[1]:前提是上述语言有合适的工具链
通过这个系列,我将记录大致整个旅程。
有何不同?
Slate 是强类型的。所以这是它与众不同的地方。但我还想添加一些功能,比如运算符重载、对象扩展(比如<Object>.prototype
在静态类型语言中,在“上添加”操作符)等等。
我可以用它嗎?
从技术上讲是的!如果你想编译上面的程序并在你自己的支持 WebAssembly 的浏览器中运行它,那么你可以执行以下操作:
import * as slate from "https://rawgit.com/nektro/slate/master/src/slate.js"
const slate_program = `
/**
*
*/
//
export const expected = 80;
//
export function main(): i32 {
return 48 + 32;
}
`;
Promise.resolve(slate_program)
.then(x => slate.parse(x))
.then(x => x.instance)
.then(x => x.exports)
.then(x => {
// `x` == { expected: 80, main: func() { [native code] } }
});
你是怎么做到的?
与任何其他语言一样,制作编译器有许多类似的步骤,并且所有步骤都在 Slate 中进行。
- 词法分析
- 解析器
- 语义分析器
- 代码生成
- 链接器
1.词法分析
这一步之所以简单,是因为当我创建 HTML 预处理器并将其添加到我的basalt JavaScript 库时,这部分用到的大部分代码已经写好了。Slate 词法分析器的代码可以在这里找到。
我们的词法分析器会获取程序的文本,并为我们做一些非常方便的事情。它必须删除注释,并将代码转换为带有数据的标记列表,以便我们稍后将其传递给解析器。
因此,在正确设置词法分析器后,basalt 将把我们的测试程序转换为类似下面的代码。
[
Key("export"),
Key("const"),
Id("expected"),
Symbol(=),
Int(80),
Symbol(;),
Key("export"),
Key("function"),
Id("main"),
Symbol("("),
Symbol(")"),
Symbol(":"),
Id("i32"),
Symbol("{"),
Key("return"),
Int(48),
Symbol("+"),
Int(32),
Symbol(";"),
Symbol("}")
]
2. 解析器
当我编写 HTML 预处理器时,这部分流程也非常复杂,所以解析也是basalt 中的一个模块。Basalt 帮助我们构建了解析器,但我们仍然需要添加所有必要的功能。Slate 的解析器在这里。熟悉计算机科学的朋友,我们正尝试通过伪上下文无关语法创建一种形式语言。ANTLR是该领域的另一个大型项目,旨在创建一个格式更类似于巴科斯范式的词法分析器/解析器。
简而言之,我们必须想出一系列模式,这些模式可以获取我们之前的标记列表并将其压缩为一个表达式,然后我们可以稍后对其进行分析以创建我们的程序。
经过该过程后,我们的测试程序看起来更像这样:
注意:我跳过了代码演示部分,因为解析器的输出非常冗长,下一步我们将对其进行压缩以显示相同的信息,但采用更有用的格式
3.语义分析器
这部分由 Slate 中的“转换器”完成,它从解析器获取非常详细的输出,对其进行验证,然后生成AST。Slate转换器的源代码可以在这里找到。
那么现在我们的程序是什么样的?
File(
Export(
Const(
"expected"
80
)
)
Export(
Function(
"main"
Parameters(
)
"i32"
Block(
Return(
Add(
48
32
)
)
)
)
)
)
4.代码生成
呼!快完成了!现在我们有了一个不错的 AST,但现在需要将其编译为 WebAssembly,以便能够通过WebAssembly.instantiateStreaming()
等方式运行。为了简化操作,我决定让我的编译器生成文本格式(而不是二进制格式)的 WASM ,然后使用wabt将文本转换为二进制 WASM。相信我,我喜欢 WebAssembly 及其含义,但即使是尝试弄清楚文本格式也很困难。目前关于这些格式的文档很少,我所依赖的大部分是 WASM 平台规范测试和各种 WASM 测试环境的输出。
从我们的 AST 生成 WAST 的代码实际上是附加在转换器发送出的对象上的,因此该代码在这里。生成上述 WAST 后,我们应该得到以下内容:
(module
(memory $0 1)
(global i32 (i32.const 80) )
(export "expected" (global 0) )
(func (export "main") (result i32)
(i32.add (i32.const 48) (i32.const 32) )
)
)
万岁!🙌
5. 链接器
目前我们实际上已经完成了。导入功能目前尚未实现,而且还没有标准库,所以这个阶段必须稍后再进行。
感谢阅读!如果你喜欢这篇文章,请告诉我你对 Slate 未来的期待,敬请期待!
未来将推出:
- 设计理念和长期目标
- 更多运营商
- 类型推断以添加对浮点数和对象的支持
- 变量
if
,while
,for
, ETC- 字符串
- 更多功能
- 课程
- 元编程
可节省您滚动时间的链接:
在 GitHub 上关注 Slate!https://github.com/nektro/slate
在 Twitter 上关注我!https://twitter.com/nektro
在 Dev 上关注我!https://dev.to/nektro