2 个版本
0.1.1 | 2020 年 2 月 3 日 |
---|---|
0.1.0 | 2019 年 9 月 15 日 |
#24 in #parse-input
每月 30 次下载
用于 gameshell
32KB
618 行
A zero-allocation, no_std, lisp-inspired command language parser for custom interpreters.
这里有一个示例
use metac::{Data, Evaluate};
struct Eval { }
impl Evaluate<()> for Eval {
fn evaluate(&mut self, statement: &[Data]) -> () {
for part in statement {
match part {
Data::Atom(string) => {}
Data::Command(command_string) => {}
}
println!("{:?}", part);
}
}
}
let mut eval = Eval { };
eval.interpret_single("Hello (World 1 2) 3").unwrap();
您只需在一个结构体上实现 Evaluate
特性,然后,在该结构体上调用 interpret
。
这允许您将任何内容放入结构体中,您决定解释器如何工作。这个库为您做的事情是将输入解析为两件事
- 原子 - 基本是字符串
- 命令 -
()
封闭的文本。
注意,metac 不会展开嵌套表达式,您需要自己完成。嵌套语句 something (alpha (beta gamma))
将被解析为 [Atom("something"), Command("alpha (beta gamma)")]
。您的评估器决定是解析内容还是用于其他目的。
更有趣的示例
use metac::{Data, Evaluate};
use std::collections::HashMap;
struct Eval {
hashmap: HashMap<String, String>,
}
impl Eval {
fn register(&mut self, key: &str, value: &str) {
self.hashmap.insert(key.into(), value.into());
}
}
impl Evaluate<String> for Eval {
fn evaluate(&mut self, statement: &[Data]) -> String {
if statement.len() == 2 {
if let Data::Atom("Get") = statement[0] {
if let Data::Atom(key) = statement[1] {
return self.hashmap.get(key).unwrap().clone();
}
}
}
"".into()
}
}
let mut eval = Eval { hashmap: HashMap::new() };
eval.register("my-variable", "my-value");
assert_eq!("my-value", eval.interpret_single("Get my-variable").unwrap());
从这里我们可以设置更复杂的环境,回调等。一切都取决于实现者。
多行支持
因为这是一种类似于 shell 的语言,所以它本质上非常注重行。将 "a b c\nd e f" 输入解释器将单独解释每一行。
但是,有时非常希望在多行上编写代码。在 metac 中,唯一的方法是使用括号或 interpret_single
use metac::{Data, Evaluate};
struct Eval { }
impl Evaluate<usize> for Eval {
fn evaluate(&mut self, statement: &[Data]) -> usize {
statement.len()
}
}
let mut eval = Eval { };
assert_eq!(5, eval.interpret_single("This is\na single statement").unwrap());
// Note: The return value is the result of interpreting the last statement, which is why
// it returns 3 instead of 2 (the first statement) or 5 (the sum).
assert_eq!(3, eval.interpret_multiple("Here are\ntwo unrelated statements").unwrap());
assert_eq!(5, eval.interpret_single("Here are\ntwo related statements").unwrap());
// Because the "\n" was present during an opening parenthesis, both lines are considered
// part of the same statement, hence 5 elements in this statement.
assert_eq!(5, eval.interpret_multiple("This is (\na) single statement").unwrap());
依赖项
~73KB