2 个版本

0.1.1 2020 年 2 月 3 日
0.1.0 2019 年 9 月 15 日

#24 in #parse-input

每月 30 次下载
用于 gameshell

LGPL-3.0-or-later

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

这允许您将任何内容放入结构体中,您决定解释器如何工作。这个库为您做的事情是将输入解析为两件事

  1. 原子 - 基本是字符串
  2. 命令 - () 封闭的文本。

注意,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