Wait the light to fall

Raku Other Impl

焉知非鱼

Raku Other Impl

(这是同一作者的法语文章 Raku en 2020 的翻译/改进版。)

感谢 Elizabeth Mattijsen 帮助校对和提供建议。

Table Of Contents #

Raku 的历史

Raku 解释器和虚拟机的历史真的不简单…如果你听说过 “Parrot”、“PIR”、“PASM”、“Pugs”、“Rakudo”、“MoarVM”、“NQP”、“Rakudo on JVM”、“Rakudo on Parrot”、“Mildew”、“Ponie”,但你对所有这些实现感到困惑,那么这篇博文就是为你准备的。

我做了一些研究,以澄清所有的历史和技术细节,并将所有的结果收集在这里,加上几个自制的原始草图,使其对你来说非常清晰。

Lot of original sketches

Raku 的诞生 #

Raku 诞生于 2000年7月18日,源于一个著名的事件:约翰-欧文特在一次会议上把咖啡杯扔到墙上

改名字的过程: Perl 6 → Raku #

一种改变其名称的编程语言…这并不经常发生!"。

最近,Raku 庆祝了它的第二年(或21年)。以下是改名过程。

  1. 很久以前(大约 2005 年),人们讨论过一个别名,但后来不了了之。
  2. 在回答一个问题时,Larry Wall 提出了一个别名
  3. Perl 6 社区的一些人要求使用这个别名
  4. 并由 Larry 验证
  5. 后来,核心团队的一个成员(Elizabeth Mattijsen)在 Raku 的官方 GitHub 上开了一个"问题",要求改名。

Issue from Elizabeth

  1. 然后,Elizabeth 向 Raku 的 Git 官方仓库提出了一个合并请求(要求维护者投票)。

Pull Request from Elizabeth

  1. 人们投票支持(或弃权),然后是 Larry Wall 的"祝福"。

Comment from Larry Wall

  1. 改名完毕,请欢迎 Raku!

下面是改名过程中的有关链接:

编译器、框架和虚拟机

在这第二部分中,我将详细介绍 Raku 语言过去的实现情况。准备好了,首字母缩写词就要来了!

Scrabble letter

哪种是"官方"实现? #

简短的回答。Rakudo 和 MoarVM。

(关于 Rakudo/MoarVM 的细节在本系列的前一篇博文中)

最初的决定是,没有任何实现会被定义为 Raku 的"官方"实现,而是说 “Raku 是通过官方测试套件的东西”。事实上,自2012年以来,有一个事实上的官方实现,即 Rakudo + MoarVM。

在此之前,有 Parrot 框架(2002-2012)以及 Pugs(2005-2007)和其他各种编译器和运行时环境(Mildew、Niecza、Yapsi…)。这个技术和历史部分将在本文的最后讨论。但让我们回过头来谈一谈开始。

最早宣布创建 Raku 的时间可以追溯到 2000年7月19日。Larry Wall 的想法是使其成为一个超社区项目,直到语言设计,所以他将从要求对规范做出贡献开始。这导致了 361 个 RFC,Larry Wall 从中产生了启示录,然后由 Damian Conway 在诠释中解释,后来又在提要中进一步详细说明。

RFC Apocalypses Synopses

为历史学家或好奇心强的人提供的链接:

Parrot

创建于 2002 年,该框架和 [Parrot 虚拟机](http://docs.parrot.org/parrot / latest / html)长期以来一直是 Raku 实现的核心(今天已经不是这样了)。Parrot 诞生于一个愚人节,宣布 Perl 和 Python 的统一,甚至即将发行一本关于这个主题的书。

Announcement of the unification of Perl and Python

为什么要建立一个新的虚拟机?

2001 年对 JVM 进行了研究,但认为它不适合动态语言(2010 年仍然不适合,更别提 2021 年了)

编译 #

Parrot 提供的不仅仅是一个虚拟机,Parrot 是一个语言创建、编译和执行框架。这个框架使建立高级语言(HLL)成为可能,而且很容易和快速。它已经被 Rakudo 实践了很长时间。

PCT #

PCT 是 Parrot Compiler Tools 的缩写。它的目的是能够创建一个编译器和一个高级语言执行环境(HLL)。

PCT

PCT 是用 PIR 写的 (请看下面的汇编部分).

PAST #

PAST 是 Parrot Abstract Syntax Tree 的缩写:语法树的内部表示法。

HLL #

HLL 是 High Level Language 的缩写。

PGE #

PGE 原名为 P6GE,PGEPerl Grammar Engine 的缩写。以 HLLCompiler 为基础。一个 PGE 规则看起来像这样。

rule term   { <number> | \( <expr> \) }
rule number { \d+ }
rule expr   { <term> ( '+' <term> )* }

PGE 被另一个 Raku 编译器 Pugs 所使用(见下文)。

TGE #

TGE 是 Tree Grammar Engine 的缩写。

PACT #

PACTParrot Alternate Compiler Toolkit 的缩写。 PACT 是 PCT 的替代方案,因为 PCT 被认为太有限。

汇编 #

PASM #

PASM 是 Parrot assembly language (PASM) 的缩写。低级别的代码已准备好由 Parrot VM 转换和执行。PASM 代码看起来像这样。

  set     I1, 1
REDO:
  gt      I1, 10, END
  print   I1
  print   " "
  inc     I1
  branch  REDO
END:
  print "\n"
  end

参考:

IMCC #

IMCC 是 Intermediate Code Compiler 的缩写。 它是一个创建和运行 Parrot 字节码的替代工具

IMCC 带来了自己的语言,通常被称为 Parrot 中间语言(PIR)。IMCC 嵌入了 Parrot 的运行环境,因此 IMCC 可以从 PIR 编译到 PASM,然后从 PASM 编译到 PBC,然后执行这个字节码。IMCC 还可以进行优化,尽管它默认不进行优化。

PIR #

PIR 最初被称为 IMC,它是 PASM 的一种叠加,而不是一种高级语言。包含 PIR 代码的文件的后缀为 “.imc”

这就是 PIR 的样子。

.sub loopy
        .local int counter
        counter = 0
LOOP:   if counter > 10 goto DONE
        print counter
        print " "
        inc counter
        goto LOOP
DONE:
        print "\n"
        end
.end

你可以从这个 IMCC 介绍或这篇关于如何编写 PIR 的文章中了解更多。请看这里的 PIR 例子或甚至 [FR mongueurs 关于 PIR 的详细文档](http://articles.mongueurs.net/magazines/linuxmag122 .html)。

Execution #

NCI #

NCI 是 Native Call Interface 的缩写。

PMC #

PMC 是 PolyMorphic ContainerParrot Magic Cookies (在虚拟机中表示数据的方式) 的缩写。

PBC #

PBC 是 Parrot Byte Code 的缩写。

Parrot 虚拟机 #

Parrot 虚拟机是一个基于注册表的虚拟机,它不是"标准"(如JVM)。

以下是 Parrot 虚拟机的一些特点。

  • 能够管理静态和动态语言
  • 写时复制
  • 管理连续性和封闭性
  • 可以嵌入到 C 代码中
  • 多态容器(灵活的类型存储)

很容易将 Parrot 包含在 C 代码中或在 Parrot 中调用 C([原生调用接口](http://docs.parrot.org/parrot/latest/html/docs/pdds/draft/pdd16_native_call .pod.html))。

基于 Parrot 的 Raku 实现(2002-2012) #

PCT IMCC Parrot VM

或者用一个合并的 IMCC 和 Parrot 阶段(后来因为 IMCC 包含 Parrot)。

PCT IMCC

下面是一个更详细的/技术图表(取自 Parrot 文档)。 How Parrot works

许多细节可在 Parrot 设计文档中找到。

Parrot 的问题 #

如果说 Parrot 最初处于 Raku 的中心,那么随着时间的推移,这种情况已经发生了变化。

  • 2008: “虽然 Parrot 是长期部署 Perl 6 的最可靠的解决方案,但另一方面,事实证明 Parrot 所接受的挑战比之前预期的要消耗更多的时间和资源。” (Perl 基金会新闻)
  • 2013: “最新的消息是,Parrot 虚拟机不再是唯一一个享受 Rakudo 独家服务的人了。” ([关于 Perl 6 的一切](http://www.josetteorama.com/all-about-perl-6 -interview-of-jonathan-worthington-part-1-of-3 /))
  • 沟通问题
  • Parrot 逐渐远离了Perl 6(通过变得更加通用)。

渐渐地,Rakudo 编译器已经从 Parrot 中解放出来,现在正瞄准新的虚拟机。

Pugs (2005-2007)

从这里我们开始考古,真正的考古。

在他短暂的存在中,Pugs 探索了许多架构选择。Pugs 指的是解释器、编译器、运行时环境和测试套件。编译器可以编译成 Haskell、JavaScript、Perl 5 或 PIR(代表 Parrot,如果你记得的话)。

Pugs compilation flow

Pugs 是用 Haskell 编写的,在 2007 年后陷入了休眠状态。

编译 #

下面是围绕 Pugs 实现构建的概念。

PCR #

PCR 是 Pugs Compiler Rules 的缩写。这是 Raku 的正则表达式引擎的 Perl 5 实现。PCR 在 Pugs 中取代了 PGE。

LREP #

LREP 演变成 Pugs::Compiler,后来又演变成 MiniPerl6

Pugs::Compiler #

Pugs::Compiler 是一套用于编译 Raku 的 Perl 5 模块。

MiniPerl6 #

曾是 Pugs 的一部分,但在一个单独的目录中。MiniPerl6 变成了 KindaPerl6,然后是 Perlito6

KindaPerl6 #

KindaPerl6 或 KP6 是一个 Raku grammar 的 Raku 实现,在 Perl 5 中具有引导功能。KindaPerl6 是由 MiniPerl6 构建的。

Execution #

PIL #

PIL 是 Pugs Intermediate Language 的缩写。PIL 不是人类可读的格式,而是 Pugs 内部的一个抽象的语法树。

PIL-Run #

Pugs PIL Perl

PIL-Run 是建立在一组读取和运行 PIL 的 Perl 5 模块之上的。PIL-Run 是 Pugs 在 Perl 5 中的后端…在开始时。

基于 Pugs 的实现 #

Pugs + 各种后端 #

“Pugs compiles and executes” Pugs compile and run

“Pugs compiles for Parrot (PIR)” Pugs PIR

对PIR的编译是分两个阶段进行的,小编把它放大。 Pugs PIL PIR

“Pugs compiles (transpiles?) To JavaScript” Pugs JS

“Perl compiles (transpiles?) To Perl 5” Pugs Perl 5

v6 #

v6-pugs 然后是 v6-alpha 和现在的 v6.pm) 是对 Pugs 的完全重写,使用了 Raku(Pugs::Compiler 和相关模块)和 Perl 5 的混合。它重用了 PIL-Run 的运行环境和"CPAN 的一半"的代码:grining。

现在 v6 在 Perlito6 中发布。v6.pm 是 Perlito 和 Pugs 在 Perl 5 中的前端。

Perlito #

Perlito 项目是由 Flavio S. Glock 领导的。Perlito 项目实际上包含了多种语言的多个编译器,针对各种后端。

  • 将 Perl 5 编译成 Java 源代码
  • 在 JVM 中直接运行 Perl 5
  • 将 Perl 5 编译成 JavaScript 源代码,直接在浏览器或 Node.js 中运行 Perl 5
  • 将 Raku 编译为 JavaScript 源代码,直接在浏览器或 Node.js 中运行 Perl6
  • 从 Perl 5 编译到 Perl 5
  • 从 Raku 编译到 Perl 5
  • 从 Raku 编译到 Python 2.6
  • 从 Perl 5 编译到 Perl 6 (正在进行中)
  • 从 Raku 编译到 Ruby 1.9 (正在进行中)
  • 从 Raku 编译到 Go (正在进行中)
  • 从 Raku 编译到 Common Lisp (SBCL) (正在进行中)

他不能做的一件事是把 Perl 5 翻译成 Raku。

MiniPerl6 和 KindaPerl6 组成了 Perlito6。Perlito5 是 Perlito6 到 Perl 5 的一个移植。它是 “用 Perl 5 实现的 Perl 5”。Perlito5 本身是用 Perl 写的。另一方面,Perlito6 是用 Raku 编写的。

Perlito 只实现了 Raku 的一个子集,称为"有用的子集",它:

  • 没有列表上下文
  • 没有继承
  • 没有 laziness
  • 有闭包,但没有协程或连续过程
  • 没有 multis

这个"有用的子集"有点类似于 NQP(关于 NQP 的细节,请看之前的博文)。

其它编译器、运行时环境和虚拟机

在这一部分,我将继续我对围绕编译器、运行时环境和传统虚拟机的倡议的巡视。

STD 和 viv #

STD 和 viv 是 Larry Wall 的作品。

我们在 STD 中发现了 Raku 的 grammar…用 Raku 写的(当时还没有编译器!)。😏 这是引导问题的开始 😀

VIV 或字面上的罗马数字 “VI → V”(因此是 “6到5”)是一个能够从 Perl 6 转换到 Perl 5 的模块。

SMOP #

最初称为 YAP6,SMOP 代表简单元对象编程

SMOP 是用 C 语言为 Raku 编写的编译器和运行时环境,但我们有时说 SMOP 只指运行时环境(它可能是其他编译器的目标)。

SMOP YAP6

SMOP 不是一个虚拟机,而是一个类似于 Perl 5 的运行环境,同时具有管理 Raku 的功能。

Mildew #

Mildew 是一个 STD 到 SMOP 的编译器。

Mildew SMOP

它直接使用了 STD grammar。

Elf #

Elf 是一个用 Raku 编写的编译器,具有 Ruby 语法。它可以发行 Perl 5 或 Lisp。它从未完成。人们期望 Elf 能够针对 SMOP。

Ponie #

Ponie 是 Perl On a New Internal Engine 的缩写。这涉及到在 Parrot 虚拟机中运行 Perl 5。在 2006 年停止了。

公告 Jesse Vincent

Ponie

Punie #

Punie(直接引用了 Ponie)是 Parrot 的一个 Perl 1 编译器。

Yapsi #

Yapsi 是 Yet Another Perl Six Implementation 的缩写。它是对编译器及其 Raku 运行环境和 Raku 虚拟机的实现。

Yapsi

SIC means (S??) Instruction Code, 这是 Yapsi 自己的字节码。

Niecza #

Niecza 是一个用 C# 编写的针对 CLR(Mono)的 Raku 编译器。

Niecza Mono

Topaz #

Topaz 是在 Perl 6 之前开始用 C++ 重写 Perl 5 的核心,最后放弃了。

Sapphire #

Sapphire是 2000年9月对 Perl 5 内部结构的另一次重写,在 Perl 6 公布后不久。更多的是实验,而不是其他的东西。

吁!这是最后一个了。我们完成了。 😀

结论

在 Raku 以及它的历史和它的实现的历史中可以找到许多有趣的概念(尽管它们中的大多数都已经是消失的世界的一部分了,但它们很值得我们仔细研究)。

我希望这篇冗长的博文能够拨开 Raku 实现的曲折迷雾,了解它的历史,并突出该语言的概念。