#编程语言 #阿拉伯 #解释器 #伊斯兰

bin+lib qalam

Qalam 编程语言的解释器。Qalam 是一种受伊斯兰/阿拉伯术语启发的、极其简单易懂的、解释型编程语言。

1 个不稳定版本

0.1.0 2024 年 8 月 21 日

127编程语言 中排名

Download history 73/week @ 2024-08-15

74 每月下载量

MIT 许可证

140KB
3.5K SLoC

qalam

受伊斯兰/阿拉伯术语启发,简单易懂,解释型编程语言

目录

简介

作为一个学习练习,为了真正磨练我的技能,我想自己编写一种编程语言。为了实现这一目标,我正在遵循名为《 Crafting Interpreters by Robert Nystrom》的精彩教程。

罗伯特会逐步介绍创建名为 Lox 的编程语言的全过程,而我并不想简单地遵循教程并复制粘贴代码。我发现,当你稍微改变教程时,真正的学习才会发生,这样你可以有更深入的理解。

为了做到这一点,我决定为该语言创建自己的语法,其功能与 Lox 相同。我还决定使用 Rust 而不是 Java 来创建语言,这样我就不可能复制粘贴代码。

使用 qalam

  1. 安装 qalam 解释器
cargo install qalam
  1. 创建一个 .qlm 文件,其中包含你的源代码
echo "qul \"hello world!\"" > main.qlm
  1. 运行 qalam 代码
qalam main.qlm
>> hello world!

语法

关键字

语法 含义/灵感 用法
niyya 意图。表示存储值的意图。 变量声明
amal 善行/行动。函数执行某些操作(行动/善行) 函数声明
radd 返回(阿拉伯语) 返回语句
qul 说(阿拉伯语) 打印语句
ghaib 未见,隐藏。表示值不存在 空值
niyya a = 1;
niyya b = 2;

amal add(a, b) {
  radd a + b;
}

qul add(a, b);
// prints 3

条件语句

语法 含义/灵感 用法
shart 条件。如果条件得到满足,则执行某些操作。 如果语句
illa 否则。不言而喻 否则语句
ilshart shart 和 illa 的组合 else-if 语句
haqq 真理。布尔 true 是真理的顶峰。 布尔 true
batil 虚假。布尔 false 是虚假的顶峰。 布尔 false
wa 和(阿拉伯语)。不言而喻。 与运算符。也可以使用 &&
aw 或(阿拉伯语)。顾名思义。 或运算符。也可以使用 ||
la 不(阿拉伯语)。顾名思义。 非运算符。也可以使用 !
niyya a = haqq;
niyya b = batil;

shart(a wa b) {
  // do something
} ilshart(la a) {
  // do something
} illa {
  // do something
}

循环

语法 含义/灵感 用法
tawaf 环绕。环绕克尔白(Ka'bah)的名称,用于朝觐。表示环绕。 for 循环
baynama While(阿拉伯语)。顾名思义 While 循环
iftar 破戒。穆斯林破戒的时间称为 iftar break 语句
safar 旅行或旅行。表示循环将继续其旅程。 continue 语句
tawaf(niyya i = 0; i < 10; i = i + 1) {
  qul i; 
  // prints 0 to 9
}

niyya a = haqq;
niyya i = 0;
baynama(a) {
  shart (i < 10) {
    qul i;
    // prints 0 
    i = i + 1;
    safar;
  } illa {
    iftar;
  }
}

对象(类)

语法 含义/灵感 用法
kitab 章节(字面:书籍)(阿拉伯语)。在伊斯兰书籍中,章节被称为 kitab。类与章节类似,它们将相关的数据分组在一起。 类定义
khalaq 创建(阿拉伯语)。构造函数创建类对象。 类构造函数
nafs 自我/灵魂。在伊斯兰教中,nafs 用于描述自我的欲望。表示实例(自我)的状态。 实例访问器(JavaScript 中的 this,Python/Rust 中的 self
ulya 最高,优越(阿拉伯语)。超类优于子类。 超类访问器(JavaScript 中的 super
ibn 儿子/孩子(阿拉伯语)。子类从超类继承,就像孩子从父母那里继承一样。 类继承运算符
kitab Animal {
  khalaq(name, sound) {
    nafs.name = name;
    nafs.sound = sound;
  }

  speak() {
    qul nafs.sound;
  }
}

kitab Feline ibn Animal {
  khalaq(name, sound) {
    ulya.khalaq(name, sound);
  }

  purr() {
    qul "purr"
  }
}

niyya cat = Feline("Hurayra", "Meow");
cat.speak();
// prints "meow"
cat.purr()
// prints "purr"

类型

以下是在 qalam 中支持的内置类型

类型 描述 初始化示例
number 数值。所有数字都存储为浮点值。没有小数部分的数字被视为整数。 niyya num= 1.0;
string 字符集合。字符可以用整数索引。用双引号初始化。 niyya name= "阿马尔";
bool 布尔值真或假。 haqq = true,batil = false。 niyya is_foo=haqq;
array 任何值的集合。值可以用整数索引和设置。用方括号初始化。 niyya arr= [1, "one",haqq];

原生函数

我向程序中实现了一些原生函数

函数名称 参数 返回类型 描述
clock number 返回自纪元以来经过的时间(秒)
typeof arg:any string 将参数的类型作为字符串返回
str arg:any string 将参数转换为字符串
str2num arg:string number 将参数转换为数字。如果不可能,则抛出错误。
substr arg:string,start:number(正整数),length:number(正整数) string 返回从 start 开始,长度为 length 的子字符串
index_of arg:string,substring:string number 返回子字符串在参数中的起始索引。如果未找到,则返回 -1。
replace arg:string,old_substr:string,new_substr:string string 将参数中所有 old_substr 替换为 new_substr
len arg:string|array number 返回字符串或数组的长度。
max a:number,b:number number 返回输入的最大值
min a:number,b:number number 返回输入的最小值
pow base:number,exp:number number 将基数提升为指数的幂
random min:number,max:number number 返回范围在 minmax 之间的随机数
random_int min:number(int),max:number(int) number 返回一个在 minmax 范围内的随机整数
push arr:array,val:any ghaib 将一个值推送到数组的末尾
pop arr:array any 从数组的末尾弹出一个值并返回它。如果不存在,则返回 ghaib
数组 大小:number(正整数),:any array 创建一个大小为 size 的数组,所有值都初始化为 value
代码 字符:string number 返回一个单字符字符串的字符码。
floor 数字:number number 返回小于或等于 num 的最接近整数
ceil 数字:number number 返回大于或等于 num 的最接近整数
round 数字:number number 返回最接近 num 的整数。如果 num 在两个整数之间,则返回远离 0 的整数。

完整示例

为了展示 qalam 的功能,以下是一个反转链表的示例

kitab ListNode {
  khalaq(value, next) {
    nafs.value = value;
    nafs.next = next;
  }
}

amal list_to_string(head) {
  niyya string = "";
  niyya curr = head;
  baynama(curr != ghaib) {
    string += str(curr.value);
    shart(curr.next) {
      string += " -> ";
    }
    curr = curr.next; 
  }

  radd string;
}

niyya list = ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5, ghaib)))));

amal reverse_list(head) {
  niyya prev = ghaib;
  niyya curr = head;
  niyya next = ghaib;
  baynama(curr != ghaib) {
    next = curr.next;
    curr.next = prev;
    prev = curr;
    curr = next;
  }

  radd prev;
}

qul "Original list:";
qul list_to_string(list);
qul "Reversed list:";
qul list_to_string(reverse_list(list));

输出

Original list:
1 -> 2 -> 3 -> 4 -> 5
Reversed list:
5 -> 4 -> 3 -> 2 -> 1

更多示例

我提供了更多的示例,在 示例目录 中。您可以使用 cargo run --example <name> 运行它们,或者在示例子目录中通过使用 qalam <file_path> 运行 main.qlm 文件。

速度

qalam 是一种解释型语言,具有动态类型。然而,由于实际上没有进行任何优化,它非常慢。在 Rust 编程方面,我也是一名极端的业余爱好者,因此,它可能比 Robert 在 Java 中的实现还要慢,因为我肯定在使用 Rust 时犯了成千上万次错误。

为了展示它实际上有多慢,我将将其速度与 JavaScript 和 Python(解释型、动态类型语言)进行比较。对于比较,我将使用递归算法计算第 30 个斐波那契数的计算来使用。

以下是每种语言的脚本

Python

import time

def fib(n):
  if n <= 1:
    return n
  else:
    return fib(n - 1) + fib(n - 2)

start = time.time()
result = fib(30)
end = time.time()
print(f"{end - start}")

JavaScript

function fib(n) {
  if (n <= 1) {
    return n;
  } else {
    return fib(n - 1) + fib(n - 2);
  }
}

let start = Date.now() / 1000;
let result = fib(30);
let end = Date.now() / 1000;
console.log(`${end - start}`);

Qalam

amal fib(n) {
  shart(n <= 1) {
    radd n;
  } illa {
    radd fib(n - 1) + fib(n - 2);
  }
}

niyya start = clock();
niyya result = fib(30);
niyya end = clock();
qul(str(end - start));

每个测试都运行了 10 次,平均运行时间如下表所示

语言 平均运行时间(秒)
JavaScript 0.0185
Python 0.2238
Qalam 78.2590

JavaScript 和 Python 每次运行都不到一秒。Qalam 需要超过一分钟。尽管如此,我仍然为它能工作而感到自豪。

依赖项

~685KB
~12K SLoC