您可以在我的终端网站上尝试的解释语言
#javascript #网络开发人员 #go #webassembly

几周前我开始阅读Writing An Interpreter In Go
在阅读并实施解释器时,一个问题弹出了:如果我可以运行此问题
怎么办 我网站的终端中的口译员?

回顾一下,几个月前,我决定将我的个人website转变为
终端(阅读更多有关here的信息)。
在今天的帖子中,我将概述整个实施,但首先是预览:

preview

您可以通过在here端子中键入simia来尝试一下

这本书:学习口译员的绝佳资源

book cover

尽管这篇文章不是书评,但我想说这是一个非常好的阅读。
您可以从令牌化的基础上学习到分析输入的评估。
作者在用具体示例的所有概念中指导读者做得很好。
如果您想了解口译员和重复工作,这本书绝对是一个不错的开始!

扩展猴子语言

在书中,作者向我们介绍了Monkey语言。
它的语法非常简单,这激发了我添加更多的表达式和语法,从本质上扩展了
我渴望的语言。我想创建一种可以结合gorust
语法的语言 elixir。这就是simia出生的方式。
我仍在努力,但到目前为止,我已经增加了对:

的支持。
  • Range表达式
  • for-loop表达式以及Infix Operator in。例如
for a in 1..10 { 
  log(a); 
}
  • 支持for-loop中布尔条件的支持6
for a > 0 { 
  log(a); 
}
  • 括号是iffor-loop表达式的可选
  • 支持Elixir的pipe操作员|>
8 |> factorial() |> add(100)
  • =运算符重新分配变量
let foo = "bar";
foo = "1234";

和我的待办事项清单:

  • 支持模块
  • 支持pub
  • 为数组,字符串和地图添加更多的内置in
  • 支持mut键和控制Mustability

总的来说,我希望simia成为某种现代功能编程语言。

在浏览器中加载解释器:WebAssembly

如果您不熟悉wasm,这里是https://webassembly.org/

的报价

WebAssembly(缩写WASM)是基于堆栈的虚拟机的二进制指令格式。
WASM被设计为编程语言的便携式编译目标,从而在
上进行部署 客户和服务器应用程序的网络。

基本上,它允许我们将simia解释器(用Golang编写)转换为浏览器
的一组指令 可以理解和执行。

Monkey中这样做真的很简单,这要归功于syscall/js
包装和Arch wasm编译解释器时。
让我们看看一个简单的例子:

// main.go

package main

import (
    "syscall/js"
)

func main() {
    done := make(chan struct{}, 0)
    js.Global().Set("wasmHash", js.FuncOf(hash))
    <-done
}

func hello(this js.Value, args []js.Value) any {
    return "hello " + args[0].String()
}

注意channel我们一直在等待输入。这是必要的,因为WASM模块它是一个应用程序
而不是图书馆。因此,此应用程序应保持运行,并且在执行js.Global()...后不立即退出。

现在我们将应用程序编译到WASM:

GOOS=js GOARCH=wasm go build -o hello.wasm ./main.go 

为了加载我们的WASM,我们需要使用WASM工具GO提供

cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" . 

现在,最后一个位,我们从JS加载WASM并使用我们的奇妙的hello函数:

<html>
<head>
    <meta charset="utf-8"/>
    <script src="wasm_exec.js"></script>
    <script>
        const go = new Go();
        WebAssembly.instantiateStreaming(fetch("hello.wasm"), go.importObject).then((result) => {
            go.run(result.instance);
            console.log(window.hello("universe")); // hello universe
        });
    </script>
</head>
<body>
</body>

就是这样,服务文件并在浏览器中打开它应显示开发人员控制台的结果。
我采取了完全相同的步骤来编译和使用浏览器中的simia解释器。
WASM模块导出到对象:

  • simia:评估Simia代码并返回结果
  • 的函数
  • simia_version:解释器的版本

警告

一切都很漂亮,但我不得不退后考虑一个问题:simia具有内置功能
称为log,它使用fmt软件包将值打印到stdout。
当汇编为WASM时,fmt.Println将使用console.log作为缓冲区,因此任何log指令都将是打印的
进入浏览器控制台。

解决方案是修改内置以使用缓冲区,然后通过JavaScript传递某种缓冲区,
因此,我可以使用该缓冲区将其打印到终端元素。我可能会在
期间解决这个问题 周末,但是如果您有一个更好的主意,请在评论中告诉我。

扩展我的网站终端

当我想出将plect添加到网站中的想法时,我看了我网站中的现有代码
并确定实现这一目标所需的要求:

  • 可以按需加载WASM模块,即用户第一次从终端调用simia
  • 命令应能够 std进出。
  • REPL将使用wasm模块评估用户输入
  • ctrl-c应该“杀死”该过程并返回外壳

在其他实施此要求中,我准备了一些重构:

  • 改善错误处理,例如“命令丢失”,“错误的参数”等
  • 改进钥匙按操作并提取共同功能
  • 介绍processId。当命令执行返回进程ID时,这意味着主函数,让我们调用它 外壳,应停止处理输入。命令退出后,应调用回调以还原主函数。

就是这样,我可以说现在我的终端有一个完全有效的simia repl。

其他

我很有趣地写口译并将其加载到我的终端网站上,我肯定学会了
在此过程中很多事情。我认为写口译员对于任何开发人员来说都是一个很好的做法。

我对网站进行的所有更改均在此PR

中介绍

您还会添加什么语言或终端?
我打算在我的网站上进行某种寻宝活动,请继续关注!

ð½