1个不稳定版本
| 0.1.0 | 2022年3月20日 |
|---|
#398 in 编程语言
48KB
1.5K SLoC
Osyris
Osyris是一个无依赖的纯Rust编程语言。它是一种LISP,旨在易于嵌入。它的执行速度不是非常快,但是解析速度非常快,代码几乎立即开始执行。
API
当您将Osyris用作库时,需要了解的主要概念是Reader、Scope和eval函数。Reader将输入文件解析为表达式,Scope是从名称到变量的映射,而eval函数接受一个表达式和一个Scope并产生一个值。
以下是一个简单的示例程序
use osyris::{eval, parse, stdlib};
use std::cell::RefCell;
use std::rc::Rc;
// The code we want to execute
static CODE: &'static str = r#"
(def 'fib {bind args 'num
{if (<= num 1)
1
{+ (fib (- num 1))
(fib (- num 2))}}})
(print "fib of 20 is" (fib 20))
"#;
fn main() -> Result<(), String> {
// Create a reader which will give us expressions
let mut reader = parse::Reader::new(CODE.as_bytes());
// Create a scope, and populate it with the stdlib
let scope = Rc::new(RefCell::new(eval::Scope::new()));
stdlib::init(&scope);
// Read and eval expressions
loop {
// We get a ParseError if the syntax is wrong
let expr = match parse::parse(&mut reader) {
Ok(expr) => expr,
Err(err) => {
println!("Parse error: {}:{}: {}", err.line, err.col, err.msg);
break;
}
};
// If the returned expression is None, we reached EOF
let expr = match expr {
Some(expr) => expr,
None => break,
};
// Evaluate the expression
match eval::eval(&expr, &scope) {
Ok(_value) => (), // Ignore the return value
Err(err) => {
println!("Eval error: {}", err);
break;
}
};
}
Ok(())
}
语法
与大多数LISP类似,语法非常简单。实际上只有字符串、数字、标识符、函数调用和引号列表。
基本语法如下
- 数字字面量:
10,20 - 字符串字面量:
"hello world","with \"escapes\"",'identifier-strings - 标识符:
look-like-this,
函数调用是一个开括号,后面跟着表达式,然后是一个闭括号,如下所示:(print 10 "hello" name)。期望第一个表达式的值是一个引号列表(或内置函数)。
引号列表类似于函数调用,但前面有一个引号:'(print 10 "hello" name)。当计算时,引号列表变成表达式列表。函数通常接受一个引号列表作为参数作为回调函数。因为它们非常常见,Osyris允许您用大括号来编写它们:{print 10 "hello" name}。
示例
if 是一个函数,它接受一个条件和一到两个引号
(if (> 10 20)
{print "10 is greater than 20"}
{print "10 is not greater than 20"})
def 用于在当前作用域中引入一个值
(def 'age 32)
(print "Your age is" age)
您可以通过定义其体为引号的变量来定义函数
(def 'say-hello {print "Hello!"})
(say-hello)
函数会隐含获得一个 args 值,它包含函数参数
(def 'say-hello {print "Hello," (args 0)})
(say-hello "Bob")
您可以使用 bind 函数为参数命名
(def 'say-hello {bind 'name 'age {print "Hello," age "year old" name}})
(say-hello "Annie" 41)
标准库
当您调用 stdlib::init 时,这些值将被填充
none:None 类型的变量。(print [values...]):一个将内容打印到标准输出的函数。(+ [numbers...]):将数字相加。(- [head] [tail...]):从头部减去尾部中的数字。(* [numbers...]):将数字相乘。(/ [head] [tail...]):将头部数字除以尾部中的数字。(== [values...]):如果所有值都相等,则返回 1,否则返回 0。(!= [values...]):==的相反数。(<= [values...]):如果每个值都不大于下一个值,则返回 1,否则返回 0。(< [values...]):如果每个值都小于下一个值,则返回 1,否则返回 0。(>= [values...]):如果每个值都不小于下一个值,则返回 1,否则返回 0。(> [values...]):如果每个值都大于下一个值,则返回 1,否则返回 0。(|| [values...]):返回第一个真值,如果所有都是假值,则返回最后一个值。(&& [values...]):返回第一个假值,如果所有值都是真值,则返回最后一个值。(def <name> <value>):在当前作用域中创建一个名为name的新变量。(set <name> <value>):替换名为name的现有变量。(if <condition> <body> [else-body]):如果condition是真值,则执行body,否则如果存在,则执行else-body。(match [pairs...] [default]):根据谓词执行一组选项中的一个。示例
(def x 55)
(match {> x 10} {print "It's greater than 10"}
{< x 10} {print "It's smaller than 10"}
{print "It's neither greater nor smaller than 10"})
(while <condition> <body>):当condition执行为真值时,执行body。(do [values...]):返回最后一个值。(bind <array> [names...] <body>):将array中的值绑定到名称,然后执行body。(with [pairs...] <body>):将值绑定到名称,然后执行body。示例
(with 'x 10
'y 20
{print "x + y is" (+ x y)})
(list [values...]):创建一个列表。(dict [pairs...]):创建一个字典。示例
(dict 'name "Bob"
'age 34
'profession "Programmer")
(lazy <quoted list>):创建一个懒变量。(read <port> [size]):从port读取。如果提供了size,则读取一个块。(write <port> <data>):将data写入port。(seek <端口号> <偏移量> [基准点]):将指针移动到偏移量。默认情况下,偏移量相对于起始位置,但基准点可以是以下之一:'set、'end或'current来改变这一点。
IO 库
这些值在你调用iolib::init时被设置。
(open <路径>):以只读模式打开路径处的文件。(create <路径>):在路径处创建或截断文件,以只写模式打开。(exec <argv>):执行系统命令。