练习使用 Rust lang 编写简单的 玩具 LISP 解析器。
注:本项目是学习 Rust 的随手练习,并无实际用途。有关 LISP 的实现原理可以参考 《Build Your Own Lisp》 https://buildyourownlisp.com/
$ cargo test
$ cargo run -- --repl
$ cargo run -- path_to_script_file
例如
$ cargo run -- example/01-add.cjs
如无意外,应该能看到输出 7
。
0、1、1、2、3、5、8、13、21、34、55...
(do
(defn fib (a)
(if
(lte a 1)
a
(add
(fib (sub a 1))
(fib (sub a 2))
)
)
)
(fib 10)
)
程序运行结果应该是 55
。
(do
(defn inc_x
(x)
(fn
(i)
(add x i)
)
)
(let inc_two (inc_x 2))
(inc_two 10)
)
程序运行结果应该是 12
。
只支持整型(int64)和布尔型(字面量为 true
和 false
)两种数据。整型和布尔型被严格区分,不支持隠式转换。比如 条件分支表达式
要求 测试子表达式
的值必须为布尔型,另外 逻辑与或非
运算也要求参数必须是布尔型的数据。
do
执行一组表达式,返回最后一个表达式的值;let
在当前的作用域内绑定一个值,返回被绑定的值;if
条件分支表达式;defn
用户自定义函数的定义;fn
匿名函数的定义。
匿名函数
其实也是 用户自定义函数
,两者不同的是:
用户自定义函数
本身带有函数名称,而匿名函数
没有名称,不过匿名函数
可以通过let
表达式让它绑定到一个标识符;用户自定义函数
不捕获动态产生的作用域的标识符的值。
之所以区分 defn
以及 fn
主要是为了试验 Rust 的 Weak 和 Rc 两者的区别。
add
加sub
减mul
乘div
除gt
大于gte
大于等于lt
小于lte
小于等于eq
等于neq
不等于and
逻辑与or
逻辑或not
逻辑非