Skip to content

Commit 7a232b8

Browse files
udzuraCopilot
andcommitted
Add eval_ruby_script_float, _string, _bool functions
- Refactor common Ruby script execution into eval_ruby_script() - Add eval_ruby_script_float: returns f64 (NaN on error) - Add eval_ruby_script_string: returns C string pointer - Add eval_ruby_script_bool: returns 0 or 1 - Update EXPORTED_FUNCTIONS and add UTF8ToString - Add JavaScript wrapper functions in main.js Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
1 parent b47e329 commit 7a232b8

File tree

6 files changed

+216
-42
lines changed

6 files changed

+216
-42
lines changed

.cargo/config.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ rustflags = [
33
"-C",
44
"link-args=-o out.js",
55
"-C",
6-
"link-args=-s EXPORTED_FUNCTIONS=['_eval_ruby_script_int','_main']",
6+
"link-args=-s EXPORTED_FUNCTIONS=['_eval_ruby_script_int','_eval_ruby_script_float','_eval_ruby_script_string','_eval_ruby_script_bool','_main']",
77
"-C",
8-
"link-args=-s EXPORTED_RUNTIME_METHODS=['ccall','cwrap']",
8+
"link-args=-s EXPORTED_RUNTIME_METHODS=['ccall','cwrap','UTF8ToString']",
99
"-C",
1010
"link-args=-s MODULARIZE=0",
1111
"-C",

Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ edition = "2024"
77
mrubyedge = { version = "1.1.8", default-features = false }
88
mruby-compiler2-sys = { path = "/Users/udzura/ghq/github.com/mrubyedge/mruby-compiler2-sys", default-features = false }
99
# mruby-compiler2-sys = { version = "0.3.0", default-features = false }
10-
# mruby-math = "0.1.0"
10+
mrubyedge-math = "0.1.0"
1111

1212
[profile.dev]
1313
# FIXME: unccomment

combined.js

Lines changed: 52 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

main.js

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* eval ruby script and return integer value
33
* @param {string} input ruby code.
4-
* @return The input multiplied by 2.
4+
* @return The integer result of the Ruby script.
55
* @customfunction
66
*/
77
function EVAL_RUBY_SCRIPT_INT(text) {
@@ -12,3 +12,53 @@ function EVAL_RUBY_SCRIPT_INT(text) {
1212
[text]
1313
);
1414
}
15+
16+
/**
17+
* eval ruby script and return float value
18+
* @param {string} input ruby code.
19+
* @return The float result of the Ruby script.
20+
* @customfunction
21+
*/
22+
function EVAL_RUBY_SCRIPT_FLOAT(text) {
23+
return Module.ccall(
24+
'eval_ruby_script_float',
25+
'number',
26+
['string'],
27+
[text]
28+
);
29+
}
30+
31+
/**
32+
* eval ruby script and return boolean value
33+
* @param {string} input ruby code.
34+
* @return The boolean result of the Ruby script.
35+
* @customfunction
36+
*/
37+
function EVAL_RUBY_SCRIPT_BOOL(text) {
38+
var result = Module.ccall(
39+
'eval_ruby_script_bool',
40+
'number',
41+
['string'],
42+
[text]
43+
);
44+
return result !== 0;
45+
}
46+
47+
/**
48+
* eval ruby script and return string value
49+
* @param {string} input ruby code.
50+
* @return The string result of the Ruby script.
51+
* @customfunction
52+
*/
53+
function EVAL_RUBY_SCRIPT_STRING(text) {
54+
var ptr = Module.ccall(
55+
'eval_ruby_script_string',
56+
'number',
57+
['string'],
58+
[text]
59+
);
60+
if (ptr === 0) {
61+
return "";
62+
}
63+
return Module.UTF8ToString(ptr);
64+
}

src/main.rs

Lines changed: 100 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,117 @@
11
#![allow(clippy::not_unsafe_ptr_arg_deref)]
2-
use std::ffi::CStr;
2+
use std::ffi::{CStr, CString};
33
use std::os::raw::c_char;
4+
use std::rc::Rc;
45

56
use mruby_compiler2_sys::MRubyCompiler2Context;
7+
use mrubyedge::yamrb::value::RObject;
68

79
fn main() {}
810

11+
/// Execute Ruby script and return the result as Rc<RObject>
12+
/// Returns None if compilation or execution fails
13+
fn eval_ruby_script(text: &str) -> Option<Rc<RObject>> {
14+
let mut context = unsafe { MRubyCompiler2Context::new() };
15+
16+
// Compile the Ruby script
17+
let mrb = match unsafe { context.compile(text) } {
18+
Ok(bytecode) => bytecode,
19+
Err(e) => {
20+
eprintln!("Compilation error: {}", e);
21+
eprintln!("Please check your Ruby code and try again");
22+
return None;
23+
}
24+
};
25+
26+
// Load and execute the bytecode
27+
let mut rite = match mrubyedge::rite::load(&mrb) {
28+
Ok(r) => r,
29+
Err(e) => {
30+
eprintln!("Failed to load bytecode: {:?}", e);
31+
return None;
32+
}
33+
};
34+
35+
let mut vm = mrubyedge::yamrb::vm::VM::open(&mut rite);
36+
37+
// Execute the script and handle exceptions
38+
match vm.run() {
39+
Ok(r) => Some(r),
40+
Err(e) => {
41+
eprintln!("Runtime error: {:?}", e);
42+
None
43+
}
44+
}
45+
}
46+
47+
/// Convert C string pointer to Rust &str
48+
unsafe fn cstr_to_str<'a>(text_ptr: *const c_char) -> &'a str {
49+
let c_str = CStr::from_ptr(text_ptr);
50+
c_str.to_str().unwrap_or("")
51+
}
52+
953
// Function called from JavaScript
10-
// Receives Ruby script, executes it, and outputs the result
54+
// Receives Ruby script, executes it, and returns integer result
1155
#[unsafe(no_mangle)]
1256
pub extern "C" fn eval_ruby_script_int(text_ptr: *const c_char) -> i32 {
1357
unsafe {
14-
// Convert C string to Rust string
15-
let c_str = CStr::from_ptr(text_ptr);
16-
let text = c_str.to_str().unwrap_or("");
17-
18-
let mut context = MRubyCompiler2Context::new();
19-
20-
// Compile the Ruby script
21-
let mrb = match context.compile(text) {
22-
Ok(bytecode) => bytecode,
23-
Err(e) => {
24-
eprintln!("Compilation error: {}", e);
25-
eprintln!("Please check your Ruby code and try again");
26-
return -1;
27-
}
28-
};
29-
30-
// Load and execute the bytecode
31-
let mut rite = match mrubyedge::rite::load(&mrb) {
32-
Ok(r) => r,
33-
Err(e) => {
34-
eprintln!("Failed to load bytecode: {:?}", e);
35-
return -1;
36-
}
37-
};
58+
let text = cstr_to_str(text_ptr);
59+
match eval_ruby_script(text) {
60+
Some(result) => (&*result).try_into().unwrap_or(-1),
61+
None => -1,
62+
}
63+
}
64+
}
3865

39-
let mut vm = mrubyedge::yamrb::vm::VM::open(&mut rite);
40-
// mruby_math::init_math(&mut vm);
66+
// Receives Ruby script, executes it, and returns float result
67+
#[unsafe(no_mangle)]
68+
pub extern "C" fn eval_ruby_script_float(text_ptr: *const c_char) -> f64 {
69+
unsafe {
70+
let text = cstr_to_str(text_ptr);
71+
match eval_ruby_script(text) {
72+
Some(result) => (&*result).try_into().unwrap_or(f64::NAN),
73+
None => f64::NAN,
74+
}
75+
}
76+
}
4177

42-
// Execute the script and handle exceptions
43-
let result = match vm.run() {
44-
Ok(r) => r,
45-
Err(e) => {
46-
eprintln!("Runtime error: {:?}", e);
47-
return -1;
78+
// Receives Ruby script, executes it, and returns boolean result (0 or 1)
79+
#[unsafe(no_mangle)]
80+
pub extern "C" fn eval_ruby_script_bool(text_ptr: *const c_char) -> i32 {
81+
unsafe {
82+
let text = cstr_to_str(text_ptr);
83+
match eval_ruby_script(text) {
84+
Some(result) => {
85+
let b: bool = (&*result).try_into().unwrap_or(false);
86+
if b { 1 } else { 0 }
4887
}
49-
};
88+
None => 0,
89+
}
90+
}
91+
}
92+
93+
// Receives Ruby script, executes it, and returns string result
94+
// Returns a pointer to a null-terminated C string (caller should NOT free it)
95+
// The returned string is valid until the next call to this function
96+
static mut LAST_STRING_RESULT: Option<CString> = None;
5097

51-
result.as_ref().try_into().unwrap_or(-1)
98+
#[unsafe(no_mangle)]
99+
pub extern "C" fn eval_ruby_script_string(text_ptr: *const c_char) -> *const c_char {
100+
unsafe {
101+
let text = cstr_to_str(text_ptr);
102+
match eval_ruby_script(text) {
103+
Some(result) => {
104+
let s: String = (&*result).try_into().unwrap_or_default();
105+
match CString::new(s) {
106+
Ok(cstring) => {
107+
let ptr = cstring.as_ptr();
108+
LAST_STRING_RESULT = Some(cstring);
109+
ptr
110+
}
111+
Err(_) => std::ptr::null(),
112+
}
113+
}
114+
None => std::ptr::null(),
115+
}
52116
}
53117
}

0 commit comments

Comments
 (0)