1use std::process::Command;
2
3use o_core::{
4 engine::JSEngine,
5 error::{JSError, JSResult},
6};
7
8pub struct BinEngine {
9 path: String,
10}
11
12impl BinEngine {
13 pub fn new(path: String) -> Self {
14 Self { path }
15 }
16}
17
18impl JSEngine for BinEngine {
19 fn run(
20 &self,
21 code: &str,
22 filename: &str,
23 ) -> Result<o_core::error::JSResult, o_core::error::JSError> {
24 let result = Command::new(self.path.clone())
25 .arg("-c")
26 .arg(filename)
27 .arg(code)
28 .output()
29 .map_err(|source| {
30 JSError::internal(format!(
31 "failed to execute toolchain binary `{}`: {source}",
32 self.path
33 ))
34 .with_filename(filename)
35 .with_source(code)
36 })?;
37
38 if !result.status.success() {
39 let stderr = String::from_utf8_lossy(&result.stderr);
40 let message = if stderr.trim().is_empty() {
41 format!(
42 "toolchain binary `{}` exited with status {}",
43 self.path, result.status
44 )
45 } else {
46 format!("toolchain binary `{}` failed: {}", self.path, stderr.trim())
47 };
48
49 return Err(JSError::runtime(message)
50 .with_filename(filename)
51 .with_source(code));
52 }
53
54 let output = String::from_utf8(result.stdout).map_err(|source| {
55 JSError::internal(format!(
56 "toolchain binary `{}` returned invalid UTF-8 output: {source}",
57 self.path
58 ))
59 .with_filename(filename)
60 .with_source(code)
61 })?;
62 Ok(JSResult::String(output))
63 }
64}