brainwires_code_interpreters/
executor.rs1use crate::types::{ExecutionError, ExecutionLimits, ExecutionRequest, ExecutionResult, Language};
4
5pub struct Executor {
7 limits: ExecutionLimits,
8}
9
10impl Executor {
11 pub fn new() -> Self {
13 Self {
14 limits: ExecutionLimits::default(),
15 }
16 }
17
18 pub fn with_limits(limits: ExecutionLimits) -> Self {
20 Self { limits }
21 }
22
23 pub fn execute(&self, request: ExecutionRequest) -> ExecutionResult {
25 let request = if request.limits.is_none() {
27 ExecutionRequest {
28 limits: Some(self.limits.clone()),
29 ..request
30 }
31 } else {
32 request
33 };
34
35 match request.language {
37 #[cfg(feature = "rhai")]
38 Language::Rhai => {
39 use crate::languages::rhai::RhaiExecutor;
40 let executor = RhaiExecutor::with_limits(
41 request
42 .limits
43 .clone()
44 .unwrap_or_else(ExecutionLimits::default),
45 );
46 executor.execute_code(&request)
47 }
48
49 #[cfg(feature = "lua")]
50 Language::Lua => {
51 use crate::languages::lua::LuaExecutor;
52 let executor = LuaExecutor::with_limits(
53 request
54 .limits
55 .clone()
56 .unwrap_or_else(ExecutionLimits::default),
57 );
58 executor.execute_code(&request)
59 }
60
61 #[cfg(feature = "javascript")]
62 Language::JavaScript => {
63 use crate::languages::javascript::JavaScriptExecutor;
64 let executor = JavaScriptExecutor::with_limits(
65 request
66 .limits
67 .clone()
68 .unwrap_or_else(ExecutionLimits::default),
69 );
70 executor.execute_code(&request)
71 }
72
73 #[cfg(feature = "python")]
74 Language::Python => {
75 use crate::languages::python::PythonExecutor;
76 let executor = PythonExecutor::with_limits(
77 request
78 .limits
79 .clone()
80 .unwrap_or_else(ExecutionLimits::default),
81 );
82 executor.execute_code(&request)
83 }
84
85 #[allow(unreachable_patterns)]
86 _ => ExecutionError::UnsupportedLanguage(request.language.to_string()).to_result(0),
87 }
88 }
89
90 pub fn execute_str(&self, language: &str, code: &str) -> ExecutionResult {
92 match Language::parse(language) {
93 Some(lang) => self.execute(ExecutionRequest {
94 language: lang,
95 code: code.to_string(),
96 limits: Some(self.limits.clone()),
97 ..Default::default()
98 }),
99 None => ExecutionError::UnsupportedLanguage(language.to_string()).to_result(0),
100 }
101 }
102
103 pub fn supported_languages(&self) -> Vec<Language> {
105 crate::supported_languages()
106 }
107
108 pub fn is_supported(&self, language: Language) -> bool {
110 crate::is_language_supported(language)
111 }
112
113 pub fn limits(&self) -> &ExecutionLimits {
115 &self.limits
116 }
117}
118
119impl Default for Executor {
120 fn default() -> Self {
121 Self::new()
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128
129 #[test]
130 fn test_executor_creation() {
131 let executor = Executor::new();
132 assert!(!executor.supported_languages().is_empty());
133 }
134
135 #[test]
136 fn test_executor_with_limits() {
137 let limits = ExecutionLimits::strict();
138 let executor = Executor::with_limits(limits.clone());
139 assert_eq!(executor.limits().max_timeout_ms, limits.max_timeout_ms);
140 }
141
142 #[test]
143 #[cfg(feature = "rhai")]
144 fn test_rhai_execution() {
145 let executor = Executor::new();
146 let result = executor.execute_str("rhai", "1 + 2");
147 assert!(result.success);
148 assert!(result.stdout.contains("3"));
149 }
150
151 #[test]
152 #[cfg(feature = "lua")]
153 fn test_lua_execution() {
154 let executor = Executor::new();
155 let result = executor.execute_str("lua", "return 1 + 2");
156 assert!(result.success);
157 assert!(result.stdout.contains("3"));
158 }
159
160 #[test]
161 #[cfg(feature = "javascript")]
162 fn test_javascript_execution() {
163 let executor = Executor::new();
164 let result = executor.execute_str("js", "1 + 2");
165 assert!(result.success);
166 assert!(result.stdout.contains("3"));
167 }
168
169 #[test]
170 #[cfg(feature = "python")]
171 fn test_python_execution() {
172 let executor = Executor::new();
173 let result = executor.execute_str("python", "print(1 + 2)");
174 assert!(result.success);
175 assert!(result.stdout.contains("3"));
176 }
177
178 #[test]
179 fn test_unsupported_language() {
180 let executor = Executor::new();
181 let result = executor.execute_str("cobol", "DISPLAY 'HELLO'");
182 assert!(!result.success);
183 assert!(result.error.unwrap().contains("not supported"));
184 }
185
186 #[test]
187 fn test_language_aliases() {
188 assert!(Language::parse("python").is_some());
191 assert!(Language::parse("py").is_some());
192 assert!(Language::parse("javascript").is_some());
193 assert!(Language::parse("js").is_some());
194 assert!(Language::parse("lua").is_some());
195 assert!(Language::parse("rhai").is_some());
196
197 assert_eq!(Language::parse("python"), Language::parse("py"));
199 assert_eq!(Language::parse("javascript"), Language::parse("js"));
200 }
201}