Lemon 编程语言介绍

这篇文章来介绍一下昨天发布的 Lemon 语言 https://github.com/lemon-lang/lemon ,我先用 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 。

强制 ; 结束

除了 defclass ,其它语句都需要用 ; 结束。

函数定义

定义函数有三个关键字,def, definefunction 它们的作用 完全一样def 只是 define 的缩写。function 是为了在定义匿名函数时代码的语义更明显。

Accessor

通过 accessor 可以定义一个变量,包括函数和类,的 gettersetter

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 结束。

dictionarya['foo'] = sentinel; 会删除掉 foo 这个 key ,如果 a['foo'] = nil; 等于在字典中添加一个值为 nil 的 key 。

如何阅读 Lemon 的代码

Lemon 的核心代码在源码目录的 src 中,根据文件名就可以区分。

  1. input 处理源码文件和缓冲区。
  2. lexer 是词法分析器。生成 token.hTOKEN_* 值。
  3. parser 是语法分析器。生成 syntax.h 中的 struct syntax 语法树结点。
  4. compiler 是编译器。生成 opcode.h 中表示 OPCODE_* 的链表。
  5. peephole 是窥孔优化器。对 compiler 中生成的 OPCODE_* 链表进行窥孔优化。
  6. generator 是代码生成器。把 peephole 中优化过的 OPCODE_* 链表生成 VM 可以执行的 bytecode 。
  7. machine 是 VM 的具体实现。
  8. collector 是 GC 的具体实现。
  9. l*.c 除了 lemon.clexer.c 是 Lemon 对象系统的实现。

上面的顺序也是整个编译过程的调用顺序。

阅读代码从 main.c 是个不错的开始。Parser 是一个简单的 Recursive descent parser 。具体可以直接看 parser.c 代码很直观。Compiler 的实现比较复杂,但大致看懂就可以理解整个编译过程。Peephole 的实现并不算完整,以后还会增加,至于其它方式的优化,我还没有研究过。GC 是一个标准的 tri-color 回收器。

在 Lemon 中有几个核心对象非常重要:

  1. lframe 是栈帧的实现,对应着 machine->frame 数组,在 Lemon 中栈帧是一个标准的 Lemon 对象,这样设计有两个好处,一是方便 GC 统一处理,二是无需了解 VM 就可以实现类似 coroutine 和 continuation 这样的功能。
  2. lfunction 函数对象,所有的函数都是这个对象,包括类中的成员函数。
  3. lclasslinstance 类和对象的实现。
  4. lkarg 用 keyword 作为参数调用函数时,比如 f(a = b) ,会把 a = b 变成 lkarg 传给 lfunction
  5. lvarg 用不定数量的参数调用函数时,比如 f(*a) ,会把 *a 变成 lvarg 传给 lfunction
  6. lvarg 用不定数量的参数调用函数时,比如 f(**a) ,会把 *a 变成 lvkarg 传给 lfunction

Lemon 的对象系统

Lemon 的对象系统是整个语言的核心所在,核心在代码 lobject.hlobject.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 ,会将 12 作为参数传给 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.cextend.c 中。

结语

Lemon 刚刚发布,还欠缺大量的文档和教程,相信随着时间的推移这些都会慢慢完善,在此先感谢对 Lemon 感兴趣并愿意尝试朋友。如有问题也欢迎加入到讨论组 https://groups.google.com/d/forum/lemon-lang

Sign in or Sign up Leave Comment