13个版本
0.5.0 | 2022年12月22日 |
---|---|
0.4.5 | 2021年6月12日 |
0.4.4 | 2020年2月22日 |
0.4.3 | 2019年5月10日 |
0.1.0 | 2019年4月17日 |
#197 in 编程语言
在 2 个crate中使用(通过 gain-lep)
46KB
1K SLoC
Lep
适用于交互式控制台的迷你语言,具有小巧的代码占用。它本质上是一个糖包装的Lisp子集,类似于shell语法,受Python影响。
核心语言是函数/声明式的。它不是图灵完备的:不支持函数创建、循环和递归。支持顶层(会话作用域)的变量绑定。扩展函数可以引入副作用。
想法是Rust程序(嵌入lep)实现扩展函数,从而有效地创建一个领域特定查询或管理语言。宿主程序还负责设置REPL(读取-评估-打印循环),从而选择从哪里读取输入以及打印什么。
语法
评估是按行进行的:一行对应一个语句。一个语句产生一个可观察的结果值。
语句语法(两部分都是可选的)
!variable expression
变量名是任何非空白字符字符串,不包括 (
和 )
。表达式是正常的 s-expression,但最外层的括号可以省略。
语句返回表达式的值。如果存在 !
前缀,则值也分配给变量。如果变量名为空,则选择一个未使用的名称(例如 $1
)。如果省略 !
前缀,则值分配给 _
变量。如果省略表达式,则评估 _
变量。
示例
>> echo "foo"
foo
>> + 1 2 3
6
>> (+ _ 10)
16
>> * (/ (- 10 5) 2) 50
100
>> ()
>> cons 1 2
(1 . 2)
>> list 1 2
(1 2)
>> ! + 1 2 3
$1 = 6
>> !x + 1 2 3
x = 6
>> !y (* x 2)
y = 12
>> and (or (and x y) (or)) true false
false
>> !z
z = false
>> !
$2 = false
>> env
(($2 . false) (z . false) (y . 12) (x . 6) ($1 . 6))
语句语法优化为两步使用
- 评估一个表达式
- 决定结果是否值得记住!
没有外部括号的表达式根据第一个术语的类型评估变量/字面量或调用函数。
当第一个术语是变量或字面量且存在多个术语时,表达式被引用。
>> 1 2 3
(1 2 3)
只包含空白的语句生成 ()
并不改变变量。当用户输入空行时,嵌入程序无需评估它,可以执行其他操作。
函数
内置函数
(and arg1 arg2 ...)
(or arg1 arg2 ...)
(not arg)
(apply function arguments)
(+ arg1 arg2 ...)
(- arg1 arg2 ...)
(* arg1 arg2 ...)
(/ arg1 arg2 ...)
(car arg)
(cdr arg)
(cons arg1 arg2)
(list arg1 arg2 ...)
(drop list count)
(take list count)
(env)
自定义扩展函数的签名为 fn(args: &Rc<dyn Any>) -> Result<Rc<dyn Any>, String>
或实现 lep::Fun
或 lep::FunMut
特性。
类型
Lep 具有动态和开放的类型系统。类型 Rc<dyn Any>
(别名 lep::Obj
)用于在函数之间传递不可变值。扩展函数可以返回和接受自定义类型,但不能与内置算术函数一起使用,逻辑函数将它们的值视为真实值。
完全支持的类型
()
bool
i64
String
lep::Name
(符号)lep::Ref
(函数)lep::Pair
(一致性单元,例如列表节点)
以下值被视为不真实
()
false
0
(仅 i64)""
(仅 String)
评估
扩展函数绑定到一个 lep::Domain
对象
let mut domain = lep::Domain::new();
lep::builtin::register(&mut domain);
domain.register("nop", |args: &lep::Obj| Ok(lep::obj::nil()));
评估迭代从一个现有的 lep::State
开始,并用一个新的替换它
let mut state = lep::State::new();
loop {
match lep::eval_stmt(&mut domain, state.clone(), read_line()) {
Ok(new_state) => {
// Print result here.
state = new_state;
}
Err(msg) {
println!("error: {}", msg);
}
}
}