pipeline_script/core/
app.rs

1use crate::core::engine::Engine;
2use crate::plugin::Plugin;
3use crate::postprocessor::Visitor;
4use std::ffi::c_void;
5use std::path::{Path, PathBuf};
6
7/// 创建和配置应用程序的宏
8///
9/// 这个宏提供了一种简洁的方式来创建应用程序实例并添加插件。
10/// 生成的应用程序可以继续链式调用其他配置方法。
11///
12/// # 参数
13/// * `entry_file` - 入口文件路径(字符串字面量或表达式)
14/// * `plugins` - 插件列表数组,包含要添加到应用程序的插件实例
15///
16/// # 示例
17///
18/// 基本使用:
19/// ```rust
20/// use pipeline_script::app;
21/// use pipeline_script::plugin::builtin::BuiltinPlugin;
22/// use pipeline_script::plugin::math::MathPlugin;
23///
24/// let mut my_app = app!("main.ppl", [BuiltinPlugin, MathPlugin]);
25/// my_app.run();
26/// ```
27///
28/// 与其他配置方法链式调用:
29/// ```rust
30/// use pipeline_script::app;
31/// use pipeline_script::plugin::builtin::BuiltinPlugin;
32/// use pipeline_script::plugin::math::MathPlugin;
33///
34/// app!("main.ppl", [BuiltinPlugin, MathPlugin])
35///     .set_test_llvm(true)
36///     .add_test_llvm_file("test.ll")
37///     .run();
38/// ```
39///
40/// 空插件列表:
41/// ```rust
42/// use pipeline_script::app;
43///
44/// let mut my_app = app!("main.ppl", []);
45/// my_app.run();
46/// ```
47#[macro_export]
48macro_rules! app {
49    ($entry_file:expr, [$($plugin:expr),* $(,)?]) => {
50        {
51            let app = $crate::core::app::App::new()
52                .set_entry_file($entry_file);
53
54            $(
55                let app = app.add_plugin($plugin);
56            )*
57
58            app
59        }
60    };
61}
62
63pub struct App {
64    engine: Engine,
65    path: PathBuf,
66}
67impl App {
68    pub fn new() -> Self {
69        Self {
70            engine: Engine::default(),
71            path: PathBuf::default(),
72        }
73    }
74    #[allow(unused)]
75    pub fn register_external_function(mut self, name: &str, func: *mut c_void) -> Self {
76        self.engine.register_external_function(name, func);
77        self
78    }
79    pub fn set_test_llvm(mut self, test: bool) -> Self {
80        self.engine.set_test_llvm(test);
81        self
82    }
83    pub fn add_test_llvm_file(mut self, path: impl AsRef<Path>) -> Self {
84        self.engine.add_test_llvm_file(path);
85        self
86    }
87    #[allow(unused)]
88    pub fn register_visitor(mut self, visitor: impl Visitor + 'static) -> Self {
89        self.engine.register_visitor(visitor);
90        self
91    }
92    pub fn add_plugin(mut self, plugin: impl Plugin) -> Self {
93        plugin.apply(&mut self.engine);
94        self
95    }
96    pub fn run(&mut self) {
97        if self.engine.test_llvm {
98            for file in self.engine.test_llvm_files.iter() {
99                self.engine.run_llvm_file(file);
100            }
101        } else {
102            self.engine.run_file(self.path.clone())
103        }
104    }
105    pub fn set_entry_file(mut self, path: impl AsRef<Path>) -> Self {
106        self.path = path.as_ref().to_path_buf();
107        self
108    }
109}
110
111impl Default for App {
112    fn default() -> Self {
113        Self::new()
114    }
115}
116
117// 包含测试模块
118#[cfg(test)]
119mod tests {
120    use super::*;
121    use crate::plugin::builtin::BuiltinPlugin;
122    use crate::plugin::format_string::FormatStringPlugin;
123    use crate::plugin::math::MathPlugin;
124
125    /// 测试 app! 宏的基本功能
126    #[test]
127    fn test_app_macro_basic() {
128        // 测试使用单个插件创建应用程序
129        let _app = app!("test.ppl", [BuiltinPlugin]);
130
131        // 验证应用程序被正确创建
132        assert!(true); // 如果宏有问题,这里会编译失败
133    }
134
135    /// 测试 app! 宏使用多个插件
136    #[test]
137    fn test_app_macro_multiple_plugins() {
138        // 测试使用多个插件创建应用程序
139        let _app = app!("main.ppl", [BuiltinPlugin, MathPlugin, FormatStringPlugin]);
140
141        // 验证应用程序被正确创建
142        assert!(true); // 如果宏有问题,这里会编译失败
143    }
144
145    /// 测试 app! 宏使用空插件列表
146    #[test]
147    fn test_app_macro_empty_plugins() {
148        // 测试不使用任何插件创建应用程序
149        let _app = app!("empty.ppl", []);
150
151        // 验证应用程序被正确创建
152        assert!(true); // 如果宏有问题,这里会编译失败
153    }
154
155    /// 测试 app! 宏与链式调用结合使用
156    #[test]
157    fn test_app_macro_with_chaining() {
158        // 测试宏创建的应用程序可以继续链式调用其他方法
159        let _app = app!("chain.ppl", [BuiltinPlugin, MathPlugin])
160            .set_test_llvm(true)
161            .add_test_llvm_file("test.ll");
162
163        // 验证链式调用正常工作
164        assert!(true); // 如果有问题,这里会编译失败
165    }
166
167    /// 测试 app! 宏使用变量作为入口文件参数
168    #[test]
169    fn test_app_macro_with_variable_entry() {
170        let entry_file = "variable.ppl";
171
172        // 测试使用变量作为入口文件参数
173        let _app = app!(entry_file, [BuiltinPlugin]);
174
175        // 验证应用程序被正确创建
176        assert!(true); // 如果宏有问题,这里会编译失败
177    }
178
179    /// 测试 app! 宏的类型推断
180    #[test]
181    fn test_app_macro_type_inference() {
182        // 测试宏返回的类型是否正确
183        let _app: App = app!("type_test.ppl", [BuiltinPlugin]);
184
185        // 验证类型推断正确
186        assert!(true);
187    }
188
189    /// 测试插件列表末尾带逗号的情况
190    #[test]
191    fn test_app_macro_trailing_comma() {
192        // 测试插件列表末尾有逗号的情况
193        let _app = app!("trailing.ppl", [BuiltinPlugin, MathPlugin,]);
194
195        // 验证应用程序被正确创建
196        assert!(true);
197    }
198}