这篇文章来介绍一下昨天发布的 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… 。