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