这篇文章来介绍一下昨天发布的 Lemon 语言 github.com/lemon-lang/… ,我先用 FAQ 的形式做个快速的介绍。
FAQ
Q: 为什么开发 Lemon 语言?
A: 因为我需要一个轻量的,容易嵌入的编程语言,同时我也想创造一个语法比较稳定的语言用来 “保护” 代码财产。在 Lemon 里的许多功能我都是用函数代替语法,并尽可能的保持精简的核心代码。
Q: Lemon 容易学吗?
A: 如果有任何 C, C++, Java, JavaScript, PHP, Python 等语言的编程经验,那么几乎不需要专门去学习 Lemon 语言,Lemon 的语法 和 JavaScript 非常接近,但又同时增加了 class 等正常编语言的功能。
Q: Lemon 的效率怎么样?
A: 因为 Lemon 还是刚刚发布,开始的目标并没有专注在性能上,所以目前 Lemon 的执行效率并不算高,和 Google V8, Lua 比起来不在一个量级上,现在只在部分测试上达到了 Python 的效率。
Q: Lemon 是动态语言吗?
A: 是的,Lemon 中有一个简洁的动态虚拟机实现。
Q: Lemon 是强类型的语言吗?
A: 并不一定,我在 Lemon 的实现中,把对象系统完全抽象出来,在 VM 里,不知道一个对象的类型,至于对象是不是强类型完全取决于这个对象的实现。
Q: Lemon 支持多线程吗?
A: 不支持,线程安全是个复杂并且容易出错的东西,所以在 Lemon 里完全没有线程的概念,线程的支持需要在 C 中处理。
Q: Lemon 支持多进程吗?
A: 和线程的支持一样。
Q: Lemon 支持匿名函数吗?
A: 支持。
Q: Lemon 支持闭包吗?
A: 支持。
Q: Lemon 支持协程吗?
A: 支持。
Q: Lemon 是 FP 吗?
A: 不是。
Q: Lemon 有 GC 吗?
A: 有。
Lemon 的一些特性
声明
变量需要提前声明才可以使用,包括函数参数。这样防止了在使用变量时的 typo 定义了一个新的变量导致不容易 debug 。
强制 ; 结束
除了 def 和 class ,其它语句都需要用 ; 结束。
函数定义
定义函数有三个关键字,def, define 和 function 它们的作用 完全一样 。def 只是 define 的缩写。function 是为了在定义匿名函数时代码的语义更明显。
Accessor
通过 accessor 可以定义一个变量,包括函数和类,的 getter 和 setter 。
getter 的例子:
def f(var x) { // x 的值是 a 的原始值,此时是 nil
return 100; // 返回值是 a 的新值
}
@getter(f)
var a;
print(a); // 无论 a 的值是什么,永远都会输出 100
@getter(f) 也可以写成 @f
setter 的例子:
def f(var x) { // x 的值是赋给 a 的值,此时是 1
return 100; // 返回值是 a 的新值
}
@setter(f)
var a;
a = 1;
print(a); // 输出 100
@setter(f) 中的 'setter' 不能省略。
getter setter 可以叠加,按照距离 var 的近远,依次执行,例如:
@f3
@f2
@f1
var a;
的执行顺序为 f1 -> f2 -> f3 。
两个 NULL 值
有人说 NULL 是万恶之源,所以在 Lemon 中,有两个 NULL 。
nil 表示正常的 NULL ,它是一个变量的默认值,也是一个函数的默认返回值。
sentinel 表示非正常的 NULL ,它是表示结束或者不再需要的值。
在遍历 iterator 的过程中,返回 sentinel 会让 iterator 结束。
在 dictionary 中 a['foo'] = sentinel; 会删除掉 foo 这个 key ,如果 a['foo'] = nil; 等于在字典中添加一个值为 nil 的 key 。
如何阅读 Lemon 的代码
Lemon 的核心代码在源码目录的 src 中,根据文件名就可以区分。
input处理源码文件和缓冲区。lexer是词法分析器。生成token.h中TOKEN_*值。parser是语法分析器。生成syntax.h中的struct syntax语法树结点。compiler是编译器。生成opcode.h中表示OPCODE_*的链表。peephole是窥孔优化器。对 compiler 中生成的OPCODE_*链表进行窥孔优化。generator是代码生成器。把peephole中优化过的OPCODE_*链表生成 VM 可以执行的 bytecode 。machine是 VM 的具体实现。collector是 GC 的具体实现。l*.c除了lemon.c和lexer.c是 Lemon 对象系统的实现。
上面的顺序也是整个编译过程的调用顺序。
阅读代码从 main.c 是个不错的开始。Parser 是一个简单的 Recursive descent parser 。具体可以直接看 parser.c 代码很直观。Compiler 的实现比较复杂,但大致看懂就可以理解整个编译过程。Peephole 的实现并不算完整,以后还会增加,至于其它方式的优化,我还没有研究过。GC 是一个标准的 tri-color 回收器。
在 Lemon 中有几个核心对象非常重要:
lframe是栈帧的实现,对应着machine->frame数组,在 Lemon 中栈帧是一个标准的 Lemon 对象,这样设计有两个好处,一是方便 GC 统一处理,二是无需了解 VM 就可以实现类似 coroutine 和 continuation 这样的功能。lfunction函数对象,所有的函数都是这个对象,包括类中的成员函数。lclass和linstance类和对象的实现。lkarg用 keyword 作为参数调用函数时,比如f(a = b),会把a = b变成lkarg传给lfunction。lvarg用不定数量的参数调用函数时,比如f(*a),会把*a变成lvarg传给lfunction。lvarg用不定数量的参数调用函数时,比如f(**a),会把*a变成lvkarg传给lfunction。
Lemon 的对象系统
Lemon 的对象系统是整个语言的核心所在,核心在代码 lobject.h 和 lobject.c 中,其中最核心的是 LOBJECT_METHOD_* 值 和 struct lobject 结构体。
struct lobject 结构体定义:
struct lobject {
lobject_method_t l_method;
struct lobject *l_next;
};
l_method 是一个函数指针,函数原型是:
lobject *method(struct lemon * lemon,
struct lobject *self,
int method, int argc, struct lobject *argv[]);
一个对象所有的操作都是由 l_method 完成的,也就是说在 Lemon 中实现一个对象最少只要一个结构体和一个函数。比如表达式 1 + 2 ,会将 1 和 2 作为参数传给 integer 对象的 l_method 函数 (其中 self = 1, method = LOBJECT_METHOD_ADD, argc = 1, argv = {b}),但 VM 只保证第一个参数是 integer 这也是为什么说 Lemon 并不一定是个强类型的语言 。
l_method 也是一个对象类型区别另一个对象类型的判断条件,即如果两个对象的 l_method 指针是一样的,那么这两个对象就是同一个类型。
l_next 是 GC 用来 mark 和 sweep 的链表。
Integer 实现
除了一个特殊范围内的 integer , 其它所有的对象都是一个可以引用的指针。但为了提高性能当 integer 大于 SMALLINT_MIN 和小于 SMALLINT_MAX 时,用了 tagged pointer 实现的 small int ,当指针的 LSB 为 0 时,是一个正常的指针。LSB 为 1 时是 small int
。
除此之外 integer 并不会出现 C 中的整型溢出,integer 的精度也只取决于系统内存。具体实现在 linteger.c 和 extend.c 中。
结语
Lemon 刚刚发布,还欠缺大量的文档和教程,相信随着时间的推移这些都会慢慢完善,在此先感谢对 Lemon 感兴趣并愿意尝试朋友。如有问题也欢迎加入到讨论组 groups.google.com/d/forum/lem… 。