第八天 – Adventures in NQP Land: Hacking the Rakudo Compiler

第八天 - NQP 领地的冒险:破解 Rakudo 编译器

Day 8 – Adventures in NQP Land: Hacking the Rakudo Compiler/

对旧圣诞节经典“圣诞节十二天”的道歉,我给你一个 Raku 版本的第一行:

在圣诞节的第一天,我真正的爱给了 pod 树上的 Perl 表格……

但是我得到的表格不是很漂亮!

背景

我与 Raku 的第一次真正联系是在 2015 年春天,当时我决定检查它的状态,发现它已经准备好迎接黄金时段。在获得了该语言的一些经验之后,我开始在我可以提供帮助的地方贡献文档。我对文档的第一个贡献是清理其中没有很好呈现的表格。在我对本地主机上的 pod 表进行实验期间,我尝试了下表格:

=begin table
-r0c0  r0c1
=end table

这导致 Raku 抛出一个丑陋的, LTA(非常搓)的异常消息:

"===SORRY!=== Cannot iterate object with P6opaque representation"

我解决了这个问题,但它让我感觉不爽,所以我开始调查 pod 和 tables 的内部。这导致我在 github.com/rakudo/src/Raku/Pod.nqp 中发现了问题的根源。

事实上,许多 pod 表格问题的真正问题最终都出现在该文件中。

Not Quite Perl (NQP)

nqp 是用于构建 Rakudo Raku 编译器的中间语言。它的 git 仓库在这里。本文的其余部分是关于修改 rakudo 编译器中的 nqp 代码,其仓库地址在这里。 Rakudo 在这里也有一个网站。

在走得太远之前,我首先阅读有关 Rakudo 和 NQP 的可用信息:

然后我开始通过编写和运行一些这样的小型 nqp 文件来练习nqp编码(文件 “hello.nqp”):

say("Hello, world!");

当它被执行时,会给出预期的结果:

$ nqp hello.nqp
Hello, world!

请注意,say() 是不需要 nqp:: 前缀的少数 nqp opcodes 之一。

进入战壕

rakudo/src/Raku/Pod.nqp 文件中包含的 Raku::Pod 类的用途是将 pod grammar 匹配并将它们转换为 rakudo/src/core/Pod.pm 中的 Raku pod 类定义,供 Raku 领地上的渲染者进一步处理。对于表格,表示以 Raku 文档设计中描述的任何合法 pod 格式表示的内容概要 S26,Raku 测试套件规范和 Raku 文档必须转换为 Raku Pod::Block::Table 类如文件 rakudo/src/core/Pod.pm 中所述,使用此格式的对象:

configuration information
a header line with N cells
M content lines, each with N cells

我希望 nqp 表格 pod 处理功能非常强大,能够自动修复某些格式问题(给作者一个警告),或者抛出一个异常(优雅)并提供问题的详细信息,以便作者修复 pod 输入。

工作区和工具

我需要两个克隆版本库:rakudo 和 roast。我还需要在 github 上复刻那些相同的git 仓库,所以我可以为我的更改创建 pull 请求(PR)。我在 CPAN 模块 App::GitGot 中找到了非常方便的 Perl 5 工具。使用 got 允许我轻松设置所有四个仓库。 (请注意,got 得要求其目标 repo 不存在于所需的本地目录或用户的github 帐户中。)配置完成后,我去了一个合适的目录以包含两个 repos 并执行以下操作:

got fork https://github.com/rakudo/rakudo.git
got fork https://github.com/raku/roast.git

这导致了一个子目录rakudo和 roast 包含克隆仓库和 rakudo 和 roast github 帐户上的新复刻。在 rakudo 目录中,可以看到用于轻松创建 PR 的默认设置:

$ git remote -v
origin  git@github.com:tbrowder/rakudo.git (fetch)
origin  git@github.com:tbrowder/rakudo.git (push)
upstream    https://github.com/rakudo/rakudo.git (fetch)
upstream    https://github.com/rakudo/rakudo.git (push)

在 roast 仓库中有类似的结果。

接下来,我将 roast 仓库作为 rakudo 的子目录(“rakudo/t/spec”)重命名,所以它作为本地 rakudo 的一个子集。

最后,我创建了几个 bash 脚本,以便于在本地 repo 目录中配置 rakudo 进行安装,设置环境并运行测试:

  • rakudo-local-config.sh
  • run-table-tests.sh
  • set-rakudo-envvars.sh

(请参阅 https://github.com/tbrowder/nqp-tools 上提到的所有脚本。)

要完成本地工作环境,您需要安装一些本地模块,以便您必须更改路径并安装 zef 安装程序的本地副本。在 rakudo 目录中执行以下步骤(来自 @Zoffix 的建议):

git clone https://github.com/ugexe/zef
export PATH=`pwd`/install/bin:$PATH
cd zef; raku -Ilib bin/zef install .
cd ..
export PATH=`pwd`/install/share/raku/site/bin:$PATH
zef install Inline::Perl5

然后安装您需要的其他模块,例如:

zef install Debugger::UI::CommandLine
zef install Grammar::Debugger

Hacking

现在开始黑客入侵。准备好构建时,执行:

make
make install

make install 步骤非常关键,否则,在我们设置的本地环境中,将不会找到新的 Raku 可执行文件。

调试于我来说很费力,每次重建需要大约三分钟。调试器(raku-debug-m)会非常有用,但我无法安装所需的 Debbugger::UI::CommandLine 模块,因此它可以被本地安装的 raku-debug-m 识别。我使用的主要方法是插入print 语句,并使用 raku 的 --ll-exception 选项。值得注意的是,这位作者是一位 Raku 新手,犯了很多错误,并且并不总是记得修复,因此有了这篇文章。 (注意我可能会使用调试工具,但在我开始的时候,我没有要求帮助,也没有提供上面提供的建议。)

测试

不言而喻,一个好的 PR 将包括对变化的测试。我总是创建一个与我的 rakudo 分支同名的 roast 分支。然后我提交了两个 PR,我指的是 rakudo PR 中的 toast PR,反之亦然。我注意到 toast PR,它需要伴生 rakudo PR 通过所有测试。

见参考文献5 了解更多有关专门测试脚本的详细信息,以进行欺骗和其他深奥测试事宜。

文档

我尝试将我的修复程序保留在最新的 Raku pod 表格文档中。

NQP 经验教训

  • LTA 错误消息是生活中的事实,例如,“无法调用此对象…”,这可能是由很多事情造成的,包括拼写错误的标识符(提交 NQP 问题,早期报告可能不会很快修复)。
  • 确保所有 nqp 操作码都有 nqp:: 前缀(除了少数内置函数)
  • 在 nqp 专用沙箱中练习新代码。

成功!

现在我已经接受并合并了两个主要的Raku POD(和 toast)PR,并且我正在研究一个更“容易”的,我将在本周完成。 这些 PR 是:

1.Rakudo PR#1240 这个 Rakudo PR 为 RT#124403,#128221,#132341,#13248和#129862提供了修复程序。它伴随着 toast PR#353

这个 PR 允许上面的问题表格被正确渲染。它还添加了有问题的表的警告,添加了 Rakudo 环境变量RAKUDO_POD6_TABLE_DEBUG 以帮助用户调试表(请参阅文档,用户调试),并允许具有空列的短行正确呈现。

2.Rakudo PR#1287 这个 Rakudo PR 为 Rakudo repo 问题#1282提供了一个解决方案。它伴随着 roast PR#361。 (请注意,roast PR#361 尚未合并。)

这个 PR 允许表格视觉列分隔符('|')和('+')作为单元格数据通过在 pod 源中转义它们。

总结

  • Raku pod相对于Perl 5来说是一个很大的改进,但它还没有完全实现。
  • 在 Rakudo Perl的内部工作是有益的(并且很有趣),但是准备让你的手变脏!
  • Raku 社区是一个很好的团队。
  • 我喜欢 Rakudo Raku。

圣诞快乐,Hacking 快乐!

参考

  1. JWs Raku debugger Advent article
  2. JWs Rakudo debugger module Debugger::UI::CommandLine
  3. JWs grammar debugger module Grammar::Debugger
  4. Testing Rakudo
  5. Contributing to roast
  6. Github guide to pull requests (PRs)
  7. Raku documentation (docs)

附录

POD 工具

  • raku –doc=MODULE # where ‘MODULE’ is ‘HTML’, ‘Text’, 或其它合适的模块
  • p6doc
  • raku –ll-exception

主要的 Raku POD 渲染器

Raku 

comments powered by Disqus