rottytooth / Rivulet Public

7 stars 0 forks Branches Tags Activity

Star Notifications You must be signed in to change notification settings

rottytooth/Rivulet

Rivulet 是一种流动的链条式编程语言,使用半图形字符编写。链条不是象形文字:它的流动并不模拟计算。共有四种链条,每种链条都有自己的象征意义和语法规则。它们共同构成字形,即紧密排列的代码块,其中的链条一起执行。

这是一个完整的斐波那契数列程序:

  ╵──╮───╮╭─  ╵╵╭────────╮
  ╰─╯╰──╯│    ╰─╶ ╶╮╶╮╶╯
  ╰─────╮ │   ╭─────╯ ╰─────╮
     ╰─╯ ╷  ╰───    ───╯╷
  ╵╵─╮ ╭─╮   ╭──    ╵╵╰─╮ ──╮──╮
   ╰─╮│ ╰─╯ ╵╵╰─╯╶╮    ╴─╯ ╭─╯╭─╯
   ╰─╯╰─ ╰──╯╰────╯    ╭╴ ╵╶╯ ╶╯╶╮
    ╭─╮ ╭╴        │ ╰──────╯
    │ │ │        ╰─╮    ╭─╮ 
   │ │ ╰─╯         │   │  │
   ╰─╯      ╷     ╰──── ╰───╯╷
  ╵╵ ╭── ──╮ ╭─╮     ╵╰─╮
   ╰─╮ ╭─╯╭─╯ │     ╴─╯
    ╶╯╵╶╯ │ ╷╶╯     ╭─╮
   ╭─╮ ╰────╯ │  ╭─╮    │
   │ ╰────╮ ╭─╯ ╭╴│ │   ╭─╯
   ╰────╮ │ │ │ │ │ │   │
   ╭────╯ │ │ ╰─╯ │ ╷   ╰─╷
   ╰────╮ │ ╰─────╯ │ 
     │ ╰─────────╯╷

这是由解释器格式化为 svg 的同一程序,以及产生等效计算机指令的两个变体:

Fibonacci 1 | Fibonacci 2 | Fibonacci 4 ---|---|--- | |

⚠️ 警告


状态:版本 0.4。这是一个大部分能正常工作的解释器,也是一个生成源代码 svg 文件的工具。命令列表可能需要扩展才能提高可用性。

设计理念

Rivulet 是一种基于列表的语言,它避免了通常的分支和循环方法。链条永远不会分裂,也没有链条会被遗漏不执行。

它的书写系统受到了迷宫、Anni Albers 的 Meanders 系列以及空间填充算法的紧凑性的启发。它的书法方面借鉴了自然语言,并倾向于手工书写能力。

数据模型

Rivulet 中,数据被组织成相邻单元格的列表,默认填充零。命令应用于单个单元格或整个列表。它们采用第二个参数,即常量或另一个单元格的值。

命令也可以逐列表运行,将命令应用于一个列表的每个连续单元格,从另一个列表的相应单元格开始。虽然这些也考虑了零填充单元格,但列表到列表的命令在任一列表中保存值的最后一个单元格处结束。

第一个列表,列表 1,有时用作输出流。这是一个解释器设置,是否将它们显示为数值数据或 Unicode 字符串(其中每个值都四舍五入为最接近的整数)也是如此。

控制流

Rivulet 程序中运行每个字形的每一条链;没有等效于 "if" 语句的东西。如果一个字形导致不需要的状态,则该字形及其块的其他字形(所有相同或更高级别的连续字形)可以回滚,将执行状态设置为字形(或字形集)触发之前的状态。条件回滚是 Rivulet 中唯一的分支形式。循环仅以回滚其最后一次迭代结束。回滚的测试是单个单元格或整个列表是零或非零,由称为问题链的特殊链指示。

数据链按照它们在左上角开始的顺序运行,流经向右流动的每一列。因此,从坐标 2,0 开始的链运行,然后是 2,1,然后是 3,0,依此类推。在数据链执行后,始终运行问题链。

语法

Rivulet 细致的语法起初可能让人感到难以理解,但通过实践,它会变得易于阅读和编写。

字形

字形以标记开始:左上角的╵,以右下角的╷结束。它们不能在其正上方或下方有垂直方向的字符,否则它们会与链条混淆。字形标记之外的任何文本都将被忽略。

字形的级别由字形开头出现的╵的数量标记。级别指示字形落在较大的代码块中的位置。

字形可以垂直或并排排列。它们按照其起始标记位置的顺序读取:从上到下,从左到右。

换句话说,这个程序:

1 ╵╰──╮╰─ ╭──╯ ╶╮
2  ─┘  └─  │
3  ╭──────────┘
5  └──────── ╷
1 ╵╵   ╭───╮ ╭─
2  ╴─╮╶╯╶╮ ╷╶╯
3 ╵╰──┘  │
5 ╰───────╯

与这一个相同:

1 ╵╰──╮╰─ ╭──╯ ╶╮ ╵╵   ╭───╮ ╭─
2  ─┘  └─  │  ╴─╮╶╯╶╮ ╷╶╯
3  ╭──────────┘ ╵╰──┘  │
5  └──────── ╷ ╰───────╯

代码行

解释器以字形编号然后行号来引用代码位置。行号在每个字形中重置为 1。在第 1 行之后,它们针对每个连续的素数编号。这些数字在语义上对某些链有意义。

其他链类型使用水平行号,以素数从它们的起始挂钩计数。它们始终从第 1 行开始,并且它们的邻居在每侧都是 2。它们通过素数进行,但始终与它们的起点保持一定距离。行号每隔一行垂直排列:这是为了使垂直线不会过于紧密地排列。

这是此类链的示例:

 ╭─╮ ╭╴ ╭╴
 │ │ │  │ │
│ │ ╰─╯  │ │
╰─╯    ╰─╯
5 3 2 1  1 2

词位

Rivulet 命令是使用这些符号编写的。有些以只有上下文才能消除歧义的方式重复使用字符:

名称 | 符号 | 上下文 | 解释 ---|---|---|--- 字形开始和结束 | ╵ ╷ | 不要与另一个具有垂直读数的符号相邻 | 标记字形,Rivulet 中最小的代码块 位置 | ╵ ╷ ╴╶ | 留下间隙,以标点符号表示链的结尾,例如从左:──╶ | 对单元格的引用指针 继续 | ─ │ | 继续沿相同方向流动,例如──── | 根据链类型,它可以添加或减去其水平或垂直行号的行号,或者只是继续链 角 | ╯┘╰└ ╮┐╭┌ | 尖角或圆角具有相同的含义,并且可以互换使用 | 改变流动方向 钩 | ╯┘╰╴└╴ ╮┐╭╴┌╴ | 它是字符或字符,在某些链的开头处旋转九十度。如果它向右或向左转动,则会用半长线扩展,该半长线用于指示位置,但会翻转以扩展钩并留下间隙。 非钩开始链 | │ 上方的╷ | 没有钩的链以半长字符开始以扩展它 | 标记问题链的开始

数据链

值链

值链指示采用常量值的命令。值链(和其他数据链)以向上(如下面的第三个链所示)或向左(如前两个链所示)指向的钩开始。以下所有三个链都是值链:

1 ╵╰──╮╭──╯╶╮
2  ─┘└─  └─╮
3

5       ╷

这些值链中的每一个都写入列表 1,因为它们的钩位于第 1 行。第一个链写入第一个单元格(单元格 0),因为它首先出现在该行,第二个链写入第二个单元格(单元格 1),依此类推。

第一个链在第 1 行上向右移动两个空格(两个 ── 字符),将 1 添加两次。然后,它在第 2 行上向左移动一个 ──,减去 2。这留下零。这使得第一个链成为_零链_。应用于链的默认命令是加法赋值,因此零链通常不调用任何操作。

第二个链也是一个零链:它以与第一个链相反的顺序进行相同的运动,减去 2,然后添加回两个链。

第三个链将值 2 添加到第三个单元格或列表 1。两个零链的重要性在于标记第三个链写入列表 1 的单元格 2,而不是单元格 0。

引用链

引用链看起来与值链相同,只是它们以位置标记结束,即标点符号表示链结尾的小间隙。它出现在此处的两个顶部链中:

1 ╵╰──╮ ╭──╯
2  ╴─┘╶╮└─╶
3    └─╮
5      ╷

引用链通过字形来回移动对其引用的内容没有影响;只有它们结束的位置。

上面的第一个链不再是零链,而是对列表 2 的第一个单元格(单元格 0)的引用。从第 1 行开始的第二个链引用列表 2 的第二个单元格(单元格 1)。这是因为在这两个链之间是一个写入列表 2 的单元格 0 的链。如果我们希望两个顶部链都从列表 2 的单元格 0 读取,我们将移动其末尾到该赋值之前(此处使用位置标记的垂直版本):

1 ╵╰──╮╭────╯
2  ╴─┘╷╶╮
3    └─╮
5      ╷

操作链

默认命令是加法赋值 (+=)。要选择另一个命令,我们创建一个操作链以应用于现有的数据链。

操作链具有向下或向右指向的钩。它们直接位于它们应用的数据链下方。如果两个数据链的钩垂直对齐,则顶部操作链应用于顶部数据链,第二个应用于第二个,依此类推。

数据链的值由向左和向右的移动确定,而操作链通过垂直移动确定值。它们的行号与字形中的其他链无关,每个链都以第 1 行作为它们开始的列。它们的邻居向左和向右是第 2 行,然后是 3 和 5。

示例:此命令将列表 1、单元格 0 和 1 的值分别提高到它们的四次方:

 1 ╵╰─╮ ╰─╮
 2  │  │
 3 ╭╴└─╭╴└─
 5 │  │
 7 │  │
11 ╰─╮ ╰─╮
13  │  │ ╷
  1 2 1 2

操作链的每个值都为 4,它对应于 exponentiation_assignment,位于值 4 的数据链下。这是(不完整的)命令列表,显示哪些值分配给哪些命令:

值 | 命令 | 解释 ---|---|--- default | addition_assignment | 添加到位置,默认设置为零 0 | overwrite | 赋值,覆盖现有值 1 | insert | 在指示的单元格后插入值 -1 | subtraction assignment 2 | multiplication assignment -2 | division assignment 3 | no-op | TBD;当前仅在分配给列表时具有值 -3 | mod assignment | 单元格值与提供的参数的模数 4 | exponentiation assignment | 提高到提供的参数的幂 -4 | root assignment | 以提供的参数的幂取根 :警告:每隔一行在素数之间递增,因为块绘图字符的垂直长度比它们的水平长度长。这听起来令人困惑,但通常在视觉上很清晰。

这是两个操作链及其编号的示例:

 ╭─╮ ╭╴ ╭╴
 │ │ │  │ │
│ │ ╰─╯  │ │
╰─╯    ╰─╯
5 3 2 1  1 2

第一个链的值为:(1 - 2 + 2*3 - 5) = 2,乘法赋值。第二个链的值为 (2 * 1) - (2 * 2) = -2,除法赋值。

列表指示器

操作链还可以标记命令不应用于单个单元格(这是默认设置),而是应用于整个列表。这通过以水平移动结束操作链来指示。当出现列表指示器时,数据链保持与更新单元格时相同的顺序。如果单元格 3 具有操作链,则它仍在单元格 2 之后和单元格 4 链之前运行。

列表 2 列表

如果操作链以位置标记(微小的间隙)结束,则表明该操作应应用于引用列表的每个单元格到分配列表的每个单元格。只有当数据链也以位置标记(是引用链)结束时,这在语法上才有效。

第二个列表中具有数字的每个单元格都应用于第一个列表中的单元格。

问题链集

问题链成对出现,一个位于另一个之上。

它们共同提出了有关数据状态的问题。如果发现它不足,则字形及其同级字形(同一级别的字形)将被回滚。如果在循环中,则仅撤消最近的迭代。这是退出循环的唯一方法。

顶部问题链以垂直线开始。它以其开始位置的左侧或右侧结束(上方或下方没有语义意义)。

底部问题链直接在其伙伴上方开始。它也以其开始位置的左侧或右侧结束,并且它以垂直部分结束(指示该问题仅适用于单个单元格)或水平部分(指示要查询整个列表,答案是其答案的累积)。

问题链仅通过其开始与结束来读取,可以在字形中来回移动,填充空白空间。它们通常是装饰性的、填充间隙的线条。

如果一个项目小于或等于零,则问题行始终失败。

顶线 | 底线 | 用途 | 检查 ---|---|---|--- 左 | 水平 | 如果 | 列表(所有项目) 左 | 垂直 | 如果 | 单元格 右 | 水平 | 当 | 列表 右 | 垂直 | 当 | 单元格 如果仅测试单个单元格,则(任何)与(全部)等效

关于

没有提供说明、网站或主题。

资源

Readme Activity

Stars

7 stars

Watchers

1 watching

Forks

0 forks

Report repository

Releases 1

v0.4.0 Latest Mar 26, 2025

Packages 0

No packages published

Languages