diff --git a/.gitignore b/.gitignore index 7ac4044..fc26a52 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ /target *.wasm -*.mrb \ No newline at end of file +*.mrb + +.claude/ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 03d7ed1..e7fa715 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -636,19 +636,6 @@ dependencies = [ "simple_endian", ] -[[package]] -name = "mrubyedge" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6637cd859a862100009f116830b1b1f6e932633d574c24480ba57983e208567" -dependencies = [ - "plain", - "rand_core 0.10.0", - "rand_xorshift", - "regex", - "simple_endian", -] - [[package]] name = "mrubyedge-cli" version = "1.1.8" @@ -657,9 +644,9 @@ dependencies = [ "clap", "crossterm", "mruby-compiler2-sys", - "mrubyedge 1.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mrubyedge-math 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "mrubyedge-time 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "mrubyedge", + "mrubyedge-math", + "mrubyedge-time", "nom", "rand", "syn", @@ -667,48 +654,29 @@ dependencies = [ [[package]] name = "mrubyedge-math" -version = "0.1.0" +version = "0.1.1" dependencies = [ "mec-mrbc-sys", - "mrubyedge 1.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mrubyedge-math" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7faac1fa8bf95e7f02ca71824aebf139ed1dd20696e42e8e1c4cb8374dde2dbe" -dependencies = [ - "mrubyedge 1.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "mrubyedge", ] [[package]] name = "mrubyedge-serde-json" -version = "0.1.0" +version = "0.1.1" dependencies = [ "mec-mrbc-sys", - "mrubyedge 1.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "mrubyedge", "serde", "serde_json", ] [[package]] name = "mrubyedge-time" -version = "0.1.1" +version = "0.1.2" dependencies = [ "libc", "mec-mrbc-sys", - "mrubyedge 1.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mrubyedge-time" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583821a12194d23b55bf1fb9051d5559c9ca3481b8bf285693a20debf11fb093" -dependencies = [ - "libc", - "mrubyedge 1.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "mrubyedge", ] [[package]] diff --git a/mruby-math/Cargo.toml b/mruby-math/Cargo.toml index e2dfc3e..320c025 100644 --- a/mruby-math/Cargo.toml +++ b/mruby-math/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "mrubyedge-math" -version = "0.1.0" +version = "0.1.1" edition = "2024" authors = ["Uchio Kondo "] description = "mruby-math provides Math module for mruby/edge" license = "BSD-3-Clause" [dependencies] -mrubyedge = { version = ">= 1.1.3" } +mrubyedge = { path = "../mrubyedge" } [dev-dependencies] -mrubyedge = { version = ">= 1.1.3", features = ["default"] } +mrubyedge = { path = "../mrubyedge", features = ["default"] } mec-mrbc-sys = "3.3.1" diff --git a/mruby-math/src/lib.rs b/mruby-math/src/lib.rs index 945ed54..4a7d790 100644 --- a/mruby-math/src/lib.rs +++ b/mruby-math/src/lib.rs @@ -107,14 +107,8 @@ fn get_float_arg(obj: &RObject) -> Result { } } -// Helper function to check argument count (excluding trailing nil) +// Helper function to check argument count fn check_args_count(args: &[Rc], expected: usize) -> Result>, Error> { - let args = if !args.is_empty() && args[args.len() - 1].is_nil() { - &args[0..args.len() - 1] - } else { - args - }; - if args.len() != expected { return Err(Error::ArgumentError(format!( "wrong number of arguments (given {}, expected {})", @@ -217,23 +211,17 @@ pub fn mrb_math_exp(_vm: &mut VM, args: &[Rc]) -> Result, E } pub fn mrb_math_log(_vm: &mut VM, args: &[Rc]) -> Result, Error> { - let args_vec = if !args.is_empty() && args[args.len() - 1].is_nil() { - args[0..args.len() - 1].to_vec() - } else { - args.to_vec() - }; - - if args_vec.len() == 1 { - let x = get_float_arg(&args_vec[0])?; + if args.len() == 1 { + let x = get_float_arg(&args[0])?; Ok(RObject::float(x.ln()).to_refcount_assigned()) - } else if args_vec.len() == 2 { - let x = get_float_arg(&args_vec[0])?; - let base = get_float_arg(&args_vec[1])?; + } else if args.len() == 2 { + let x = get_float_arg(&args[0])?; + let base = get_float_arg(&args[1])?; Ok(RObject::float(x.log(base)).to_refcount_assigned()) } else { Err(Error::ArgumentError(format!( "wrong number of arguments (given {}, expected 1..2)", - args_vec.len() + args.len() ))) } } diff --git a/mruby-serde-json/Cargo.toml b/mruby-serde-json/Cargo.toml index 487660a..6b7eb54 100644 --- a/mruby-serde-json/Cargo.toml +++ b/mruby-serde-json/Cargo.toml @@ -1,17 +1,16 @@ [package] name = "mrubyedge-serde-json" -version = "0.1.0" +version = "0.1.1" edition = "2024" authors = ["Uchio Kondo "] description = "mruby-serde-json provides JSON serialization/deserialization for mruby/edge using serde_json" license = "BSD-3-Clause" [dependencies] -mrubyedge = ">= 1.1.3" -# mrubyedge = { version = "1.1.3", path = "../mrubyedge", default-features = false } +mrubyedge = { path = "../mrubyedge" } serde = ">= 1.0.228" serde_json = ">= 1.0.149" [dev-dependencies] -mrubyedge = { version = ">= 1.1.3", features = ["default"] } +mrubyedge = { path = "../mrubyedge", features = ["default"] } mec-mrbc-sys = "3.3.1" diff --git a/mruby-serde-json/src/lib.rs b/mruby-serde-json/src/lib.rs index ea8333c..c8cb96d 100644 --- a/mruby-serde-json/src/lib.rs +++ b/mruby-serde-json/src/lib.rs @@ -37,11 +37,6 @@ pub fn init_json(vm: &mut VM) { } pub fn mrb_json_class_dump(vm: &mut VM, args: &[Rc]) -> Result, Error> { - let args = if args[args.len() - 1].is_nil() { - &args[0..args.len() - 1] - } else { - args - }; if args.len() != 1 { return Err(Error::ArgumentError( "wrong number of arguments".to_string(), @@ -52,11 +47,6 @@ pub fn mrb_json_class_dump(vm: &mut VM, args: &[Rc]) -> Result]) -> Result, Error> { - let args = if args[args.len() - 1].is_nil() { - &args[0..args.len() - 1] - } else { - args - }; if args.len() != 1 { return Err(Error::ArgumentError( "wrong number of arguments".to_string(), diff --git a/mruby-time/Cargo.toml b/mruby-time/Cargo.toml index 52c6f7a..59f3c83 100644 --- a/mruby-time/Cargo.toml +++ b/mruby-time/Cargo.toml @@ -1,17 +1,17 @@ [package] name = "mrubyedge-time" -version = "0.1.1" +version = "0.1.2" edition = "2024" authors = ["Uchio Kondo "] description = "mruby-time provides Time class for mruby/edge" license = "BSD-3-Clause" [dependencies] -mrubyedge = ">= 1.1.8" +mrubyedge = { path = "../mrubyedge" } libc = "0.2" [dev-dependencies] -mrubyedge = { version = ">= 1.1.8", features = ["default"] } +mrubyedge = { path = "../mrubyedge", features = ["default"] } mec-mrbc-sys = "3.3.1" [features] diff --git a/mruby-time/src/lib.rs b/mruby-time/src/lib.rs index a2f6d6a..1977a26 100644 --- a/mruby-time/src/lib.rs +++ b/mruby-time/src/lib.rs @@ -160,7 +160,6 @@ fn mrb_time_now(vm: &mut VM, _args: &[Rc]) -> Result, Error /// Time.at(sec) or Time.at(sec, nsec) fn mrb_time_at(vm: &mut VM, args: &[Rc]) -> Result, Error> { - let args = strip_trailing_nil(args); if args.is_empty() { return Err(Error::ArgumentError( "wrong number of arguments (given 0, expected 1+)".to_string(), @@ -253,7 +252,6 @@ fn mrb_time_to_s(vm: &mut VM, _args: &[Rc]) -> Result, Erro /// Time#+ (sec as integer or float) fn mrb_time_add(vm: &mut VM, args: &[Rc]) -> Result, Error> { - let args = strip_trailing_nil(args); if args.is_empty() { return Err(Error::ArgumentError( "wrong number of arguments (given 0, expected 1)".to_string(), @@ -276,7 +274,6 @@ fn mrb_time_add(vm: &mut VM, args: &[Rc]) -> Result, Error> /// Time#- (sec as integer or float), also supports Time - Time -> Float (seconds) fn mrb_time_sub(vm: &mut VM, args: &[Rc]) -> Result, Error> { - let args = strip_trailing_nil(args); if args.is_empty() { return Err(Error::ArgumentError( "wrong number of arguments (given 0, expected 1)".to_string(), @@ -309,7 +306,6 @@ fn mrb_time_sub(vm: &mut VM, args: &[Rc]) -> Result, Error> /// Time#<=> (compare with another Time object) fn mrb_time_cmp(vm: &mut VM, args: &[Rc]) -> Result, Error> { - let args = strip_trailing_nil(args); if args.is_empty() { return Err(Error::ArgumentError( "wrong number of arguments (given 0, expected 1)".to_string(), @@ -345,7 +341,6 @@ fn mrb_time_utc_offset(vm: &mut VM, _args: &[Rc]) -> Result /// Time#localtime(offset) - returns a new Time with the given UTC offset (in seconds) fn mrb_time_localtime(vm: &mut VM, args: &[Rc]) -> Result, Error> { - let args = strip_trailing_nil(args); let self_obj = vm.getself()?; let t = get_time_data(&self_obj)?; @@ -424,14 +419,6 @@ fn local_utc_offset_secs() -> i32 { // Helper utilities // --------------------------------------------------------------------------- -fn strip_trailing_nil(args: &[Rc]) -> &[Rc] { - if !args.is_empty() && args[args.len() - 1].is_nil() { - &args[0..args.len() - 1] - } else { - args - } -} - fn get_integer_or_float_as_i64(obj: &RObject) -> Result { match &obj.value { RValue::Integer(i) => Ok(*i), diff --git a/mruby-time/tests/smoke.rs b/mruby-time/tests/smoke.rs index b259a39..078e959 100644 --- a/mruby-time/tests/smoke.rs +++ b/mruby-time/tests/smoke.rs @@ -5,6 +5,7 @@ mod helpers; use helpers::*; /// Helper: build a VM with Time initialized and a fixed Time.__source returning [sec, nsec]. +#[allow(unused)] fn make_vm_with_time_source(sec: i64, nsec: u32) -> mrubyedge::yamrb::vm::VM { use mrubyedge::yamrb::helpers::mrb_define_singleton_cmethod; use mrubyedge::yamrb::value::RObject; diff --git a/mrubyedge-cli/Cargo.toml b/mrubyedge-cli/Cargo.toml index 308d20a..05b1c81 100644 --- a/mrubyedge-cli/Cargo.toml +++ b/mrubyedge-cli/Cargo.toml @@ -15,13 +15,13 @@ path = "src/main.rs" clap = { version = "4.5", features = ["derive"] } crossterm = "0.28" mruby-compiler2-sys = "0.3.0" -mrubyedge = { version = "1.1.7", features = [ +mrubyedge = { path = "../mrubyedge", features = [ "default", "mruby-random", "mruby-regexp", ] } -mrubyedge-math = "0.1.0" -mrubyedge-time = "0.1.1" +mrubyedge-math = { path = "../mruby-math" } +mrubyedge-time = { path = "../mruby-time" } rand = "0.9.2" nom = "7.1.3" askama = "0.12.1" diff --git a/mrubyedge/COVERAGE.md b/mrubyedge/COVERAGE.md index 2eb6291..a4f80c7 100644 --- a/mrubyedge/COVERAGE.md +++ b/mrubyedge/COVERAGE.md @@ -34,6 +34,9 @@ A list of currently supported classes and methods, based on the implementations | `#method_missing` | | | `#extend` | | | `#loop` | | +| `#block_given?` | | +| `#respond_to?` | | +| `#public_send` | | | `#wasm?` | mruby/edge specific | | `#puts` | `[feature: wasi]` only | | `#p` | `[feature: wasi]` only | @@ -209,6 +212,7 @@ Exception |---|---| | `#to_s` | | | `#inspect` | `:sym` format | +| `#to_proc` | converts symbol to a proc that calls the method | --- diff --git a/mrubyedge/src/yamrb/optable.rs b/mrubyedge/src/yamrb/optable.rs index a86be59..f6e7364 100644 --- a/mrubyedge/src/yamrb/optable.rs +++ b/mrubyedge/src/yamrb/optable.rs @@ -494,6 +494,7 @@ pub(crate) fn push_callinfo( return_reg, target_class: vm.target_class.clone(), method_owner, + has_block: Cell::new(false), }; vm.current_callinfo = Some(Rc::new(callinfo)); } @@ -1023,11 +1024,16 @@ pub(crate) fn do_op_send( vm.kargs.borrow_mut().replace(map); if let Some(blk_index) = blk_index { - args.push(vm.get_current_regs_cloned(blk_index)?); + let blk_val = vm.get_current_regs_cloned(blk_index)?; + if matches!(blk_val.tt, RType::Symbol) { + let proc_val = mrb_funcall(vm, Some(blk_val), "to_proc", &[])?; + args.push(proc_val); + } else { + args.push(blk_val); + } } else { - // When no block is provided, set nil in the block register + // When no block is provided, do not push a nil placeholder vm.current_regs()[block_index].replace(Rc::new(RObject::nil())); - args.push(Rc::new(RObject::nil())); } let klass = recv.get_class(vm); @@ -1099,6 +1105,11 @@ pub(crate) fn do_op_send( push_callinfo(vm, method_id, n, Some(owner_module), a as usize); + // Set has_block flag based on whether a block was provided + if let Some(ci) = vm.current_callinfo.as_ref() { + ci.has_block.set(blk_index.is_some()); + } + vm.pc.set(0); vm.current_irep = method.irep.ok_or_else(|| Error::internal("empry irep"))?; vm.current_regs_offset += a as usize; @@ -1253,15 +1264,15 @@ pub(crate) fn op_super(vm: &mut VM, operand: &Fetched) -> Result<(), Error> { } #[allow(dead_code)] -#[derive(Debug)] -struct EnterArgInfo { - m1: u32, - o: u32, - r: u32, - m2: u32, - k: u32, - d: u32, - b: u32, +#[derive(Debug, Copy, Clone)] +pub(crate) struct EnterArgInfo { + pub m1: u32, + pub o: u32, + pub r: u32, + pub m2: u32, + pub k: u32, + pub d: u32, + pub b: u32, } impl From for EnterArgInfo { diff --git a/mrubyedge/src/yamrb/prelude/array.rs b/mrubyedge/src/yamrb/prelude/array.rs index d667fcd..c351cd5 100644 --- a/mrubyedge/src/yamrb/prelude/array.rs +++ b/mrubyedge/src/yamrb/prelude/array.rs @@ -159,11 +159,6 @@ pub fn mrb_array_new(_vm: &mut VM, args: &[Rc]) -> Result, fn mrb_array_push_self(vm: &mut VM, args: &[Rc]) -> Result, Error> { let this = vm.getself()?; - let args = if args[args.len() - 1].as_ref().is_nil() { - &args[..args.len() - 1] - } else { - args - }; mrb_array_push(this, args) } @@ -487,11 +482,6 @@ fn mrb_array_or(vm: &mut VM, args: &[Rc]) -> Result, Error> // Array#first: Returns the first element, or the first n elements fn mrb_array_first(vm: &mut VM, args: &[Rc]) -> Result, Error> { let this: Vec> = vm.getself()?.as_ref().try_into()?; - let args = if !args.is_empty() && args[args.len() - 1].as_ref().is_nil() { - &args[..args.len() - 1] - } else { - args - }; if args.is_empty() { Ok(this @@ -511,11 +501,6 @@ fn mrb_array_first(vm: &mut VM, args: &[Rc]) -> Result, Err // Array#last: Returns the last element, or the last n elements fn mrb_array_last(vm: &mut VM, args: &[Rc]) -> Result, Error> { let this: Vec> = vm.getself()?.as_ref().try_into()?; - let args = if !args.is_empty() && args[args.len() - 1].as_ref().is_nil() { - &args[..args.len() - 1] - } else { - args - }; if args.is_empty() { Ok(this @@ -555,11 +540,6 @@ fn mrb_array_shift(vm: &mut VM, _args: &[Rc]) -> Result, Er fn mrb_array_unshift(vm: &mut VM, args: &[Rc]) -> Result, Error> { let this = vm.getself()?; let mut arr = this.array_borrow_mut()?; - let args = if args[args.len() - 1].as_ref().is_nil() { - &args[..args.len() - 1] - } else { - args - }; for (i, arg) in args.iter().enumerate() { arr.insert(i, arg.clone()); } diff --git a/mrubyedge/src/yamrb/prelude/object.rs b/mrubyedge/src/yamrb/prelude/object.rs index b018123..c92dc9a 100644 --- a/mrubyedge/src/yamrb/prelude/object.rs +++ b/mrubyedge/src/yamrb/prelude/object.rs @@ -73,6 +73,12 @@ pub(crate) fn initialize_object(vm: &mut VM) { Box::new(mrb_object_raise), ); mrb_define_cmethod(vm, object_class.clone(), "nil?", Box::new(mrb_object_nil_p)); + mrb_define_cmethod( + vm, + object_class.clone(), + "block_given?", + Box::new(mrb_object_block_given), + ); mrb_define_cmethod( vm, object_class.clone(), @@ -117,6 +123,18 @@ pub(crate) fn initialize_object(vm: &mut VM) { Box::new(mrb_object_extend), ); mrb_define_cmethod(vm, object_class.clone(), "loop", Box::new(mrb_object_loop)); + mrb_define_cmethod( + vm, + object_class.clone(), + "respond_to?", + Box::new(mrb_object_respond_to), + ); + mrb_define_cmethod( + vm, + object_class.clone(), + "public_send", + Box::new(mrb_object_public_send), + ); // define global consts: vm.consts.insert( @@ -329,6 +347,17 @@ fn mrb_object_nil_p(_vm: &mut VM, _args: &[Rc]) -> Result, Ok(Rc::new(RObject::boolean(false))) } +fn mrb_object_block_given(vm: &mut VM, _args: &[Rc]) -> Result, Error> { + // CALLINFO の has_block フラグをチェック + let has_block = if let Some(ci) = vm.current_callinfo.as_ref() { + ci.has_block.get() + } else { + false + }; + + Ok(Rc::new(RObject::boolean(has_block))) +} + pub fn mrb_object_initialize(_vm: &mut VM, _args: &[Rc]) -> Result, Error> { // Abstract method; do nothing Ok(Rc::new(RObject::nil())) @@ -380,6 +409,29 @@ fn mrb_object_loop(vm: &mut VM, args: &[Rc]) -> Result, Err } } +fn mrb_object_respond_to(vm: &mut VM, args: &[Rc]) -> Result, Error> { + let method_name: String = args[0].as_ref().try_into()?; + let obj = vm.getself()?; + let klass = obj.singleton_or_this_class(vm); + let has_method = resolve_method(&klass, &method_name).is_some(); + Ok(Rc::new(RObject::boolean(has_method))) +} + +fn mrb_object_public_send(vm: &mut VM, args: &[Rc]) -> Result, Error> { + if args.is_empty() { + return Err(Error::ArgumentError( + "wrong number of arguments (given 0, expected 1+)".to_string(), + )); + } + + let method_name: String = args[0].as_ref().try_into()?; + let obj = vm.getself()?; + let method_args = &args[1..]; + + // For now, public_send behaves the same as send since we don't have visibility modifiers + mrb_funcall(vm, Some(obj), &method_name, method_args) +} + fn mrb_object_method_missing(vm: &mut VM, args: &[Rc]) -> Result, Error> { let method_name_obj = &args .first() diff --git a/mrubyedge/src/yamrb/prelude/rand.rs b/mrubyedge/src/yamrb/prelude/rand.rs index a566da1..7d7ec83 100644 --- a/mrubyedge/src/yamrb/prelude/rand.rs +++ b/mrubyedge/src/yamrb/prelude/rand.rs @@ -108,11 +108,6 @@ fn get_default_rng(vm: &mut VM) -> Rc { pub(crate) fn mrb_random_new(vm: &mut VM, args: &[Rc]) -> Result, Error> { let class = get_rng_class(vm); - let args = if !args.is_empty() && args[args.len() - 1].is_nil() { - &args[0..args.len() - 1] - } else { - args - }; let seed = if args.is_empty() { new_seed() } else { @@ -142,11 +137,6 @@ pub(crate) fn mrb_random_new(vm: &mut VM, args: &[Rc]) -> Result]) -> Result, Error> { - let args = if !args.is_empty() && args[args.len() - 1].is_nil() { - &args[0..args.len() - 1] - } else { - args - }; let seed = if args.is_empty() { new_seed() } else { @@ -194,12 +184,6 @@ fn mrb_random_seed(vm: &mut VM, _args: &[Rc]) -> Result, Er fn mrb_random_rand(vm: &mut VM, args: &[Rc]) -> Result, Error> { use rand_core::Rng; - let args = if !args.is_empty() && args[args.len() - 1].is_nil() { - &args[0..args.len() - 1] - } else { - args - }; - let self_obj = vm.getself()?; let result = match &self_obj.value { diff --git a/mrubyedge/src/yamrb/prelude/string.rs b/mrubyedge/src/yamrb/prelude/string.rs index 732b310..66aef55 100644 --- a/mrubyedge/src/yamrb/prelude/string.rs +++ b/mrubyedge/src/yamrb/prelude/string.rs @@ -421,12 +421,6 @@ fn mrb_string_slice_self(vm: &mut VM, args: &[Rc]) -> Result]) -> Result, Error> { @@ -25,3 +34,27 @@ fn mrb_symbol_to_s(vm: &mut VM, _args: &[Rc]) -> Result, Er let symbol: String = vm.getself()?.as_ref().try_into()?; Ok(Rc::new(RObject::string(symbol))) } + +fn mrb_symbol_to_proc(vm: &mut VM, _args: &[Rc]) -> Result, Error> { + let method_name: String = vm.getself()?.as_ref().try_into()?; + let rfn: RFn = Box::new(move |vm: &mut VM, args: &[Rc]| { + let recv = args + .first() + .cloned() + .ok_or_else(|| Error::ArgumentError("no receiver given".to_string()))?; + let method_args = if args.len() > 1 { &args[1..] } else { &[] }; + mrb_funcall(vm, Some(recv), &method_name, method_args) + }); + vm.push_fnblock(Rc::new(rfn))?; + let block = RProc { + is_rb_func: false, + is_fnblock: true, + sym_id: None, + next: None, + irep: None, + func: None, + environ: None, + block_self: vm.getself().ok(), + }; + Ok(RObject::proc(block).to_refcount_assigned()) +} diff --git a/mrubyedge/src/yamrb/vm.rs b/mrubyedge/src/yamrb/vm.rs index 8fe0c8a..0fc7e6f 100644 --- a/mrubyedge/src/yamrb/vm.rs +++ b/mrubyedge/src/yamrb/vm.rs @@ -895,6 +895,7 @@ pub struct CALLINFO { pub n_args: usize, pub return_reg: usize, pub method_owner: Option>, + pub has_block: Cell, } #[derive(Debug, Clone)] diff --git a/mrubyedge/tests/object.rs b/mrubyedge/tests/object.rs index 12ab4de..e85438a 100644 --- a/mrubyedge/tests/object.rs +++ b/mrubyedge/tests/object.rs @@ -317,3 +317,208 @@ fn object_loop_basic_test() { .unwrap(); assert_eq!(result, 5); } + +#[test] +fn object_block_given_with_block_test() { + let code = r#" + def method_with_block + block_given? + end + + def test_block_given_with_block + method_with_block { } + end + "#; + let binary = mrbc_compile("block_given_with_block", code); + let mut rite = mrubyedge::rite::load(&binary).unwrap(); + let mut vm = mrubyedge::yamrb::vm::VM::open(&mut rite); + vm.run().unwrap(); + + let args = vec![]; + let result: bool = mrb_funcall(&mut vm, None, "test_block_given_with_block", &args) + .unwrap() + .as_ref() + .try_into() + .unwrap(); + assert_eq!(result, true); +} + +#[test] +fn object_block_given_without_block_test() { + let code = r#" + def method_with_block + block_given? + end + + def test_block_given_without_block + method_with_block + end + "#; + let binary = mrbc_compile("block_given_without_block", code); + let mut rite = mrubyedge::rite::load(&binary).unwrap(); + let mut vm = mrubyedge::yamrb::vm::VM::open(&mut rite); + vm.run().unwrap(); + + let args = vec![]; + let result: bool = mrb_funcall(&mut vm, None, "test_block_given_without_block", &args) + .unwrap() + .as_ref() + .try_into() + .unwrap(); + assert_eq!(result, false); +} + +#[test] +fn object_block_given_with_args_and_block_test() { + let code = r#" + def method_with_args(a, b, c) + block_given? + end + + def test_block_given_with_args_and_block + method_with_args(1, 2, 3) { } + end + "#; + let binary = mrbc_compile("block_given_with_args_and_block", code); + let mut rite = mrubyedge::rite::load(&binary).unwrap(); + let mut vm = mrubyedge::yamrb::vm::VM::open(&mut rite); + vm.run().unwrap(); + + let args = vec![]; + let result: bool = mrb_funcall(&mut vm, None, "test_block_given_with_args_and_block", &args) + .unwrap() + .as_ref() + .try_into() + .unwrap(); + assert_eq!(result, true); +} + +#[test] +fn object_block_given_with_args_without_block_test() { + let code = r#" + def method_with_args(a, b, c) + block_given? + end + + def test_block_given_with_args_without_block + method_with_args(1, 2, 3) + end + "#; + let binary = mrbc_compile("block_given_with_args_without_block", code); + let mut rite = mrubyedge::rite::load(&binary).unwrap(); + let mut vm = mrubyedge::yamrb::vm::VM::open(&mut rite); + vm.run().unwrap(); + + let args = vec![]; + let result: bool = mrb_funcall( + &mut vm, + None, + "test_block_given_with_args_without_block", + &args, + ) + .unwrap() + .as_ref() + .try_into() + .unwrap(); + assert_eq!(result, false); +} + +#[test] +fn object_respond_to_existing_method_test() { + let code = r#" + def test_respond_to_existing + obj = Object.new + obj.respond_to?("to_s") + end + "#; + let binary = mrbc_compile("respond_to_existing", code); + let mut rite = mrubyedge::rite::load(&binary).unwrap(); + let mut vm = mrubyedge::yamrb::vm::VM::open(&mut rite); + vm.run().unwrap(); + + let args = vec![]; + let result: bool = mrb_funcall(&mut vm, None, "test_respond_to_existing", &args) + .unwrap() + .as_ref() + .try_into() + .unwrap(); + assert_eq!(result, true); +} + +#[test] +fn object_respond_to_non_existing_method_test() { + let code = r#" + def test_respond_to_non_existing + obj = Object.new + obj.respond_to?("non_existing_method") + end + "#; + let binary = mrbc_compile("respond_to_non_existing", code); + let mut rite = mrubyedge::rite::load(&binary).unwrap(); + let mut vm = mrubyedge::yamrb::vm::VM::open(&mut rite); + vm.run().unwrap(); + + let args = vec![]; + let result: bool = mrb_funcall(&mut vm, None, "test_respond_to_non_existing", &args) + .unwrap() + .as_ref() + .try_into() + .unwrap(); + assert_eq!(result, false); +} + +#[test] +fn object_public_send_test() { + let code = r#" + class TestClass + def hello(name) + "Hello, #{name}!" + end + end + + def test_public_send + obj = TestClass.new + obj.public_send("hello", "World") + end + "#; + let binary = mrbc_compile("public_send", code); + let mut rite = mrubyedge::rite::load(&binary).unwrap(); + let mut vm = mrubyedge::yamrb::vm::VM::open(&mut rite); + vm.run().unwrap(); + + let args = vec![]; + let result: String = mrb_funcall(&mut vm, None, "test_public_send", &args) + .unwrap() + .as_ref() + .try_into() + .unwrap(); + assert_eq!(result, "Hello, World!"); +} + +#[test] +fn object_public_send_no_args_test() { + let code = r#" + class TestClass + def greet + "Hi!" + end + end + + def test_public_send_no_args + obj = TestClass.new + obj.public_send("greet") + end + "#; + let binary = mrbc_compile("public_send_no_args", code); + let mut rite = mrubyedge::rite::load(&binary).unwrap(); + let mut vm = mrubyedge::yamrb::vm::VM::open(&mut rite); + vm.run().unwrap(); + + let args = vec![]; + let result: String = mrb_funcall(&mut vm, None, "test_public_send_no_args", &args) + .unwrap() + .as_ref() + .try_into() + .unwrap(); + assert_eq!(result, "Hi!"); +} diff --git a/mrubyedge/tests/to_proc.rs b/mrubyedge/tests/to_proc.rs new file mode 100644 index 0000000..966824f --- /dev/null +++ b/mrubyedge/tests/to_proc.rs @@ -0,0 +1,90 @@ +extern crate mec_mrbc_sys; +extern crate mrubyedge; + +mod helpers; + +use std::rc::Rc; + +use helpers::*; +use mrubyedge::yamrb::value::RObject; + +#[test] +fn symbol_to_proc_direct() { + let code = r#" + def test_to_proc_direct + sym = :upcase + proc = sym.to_proc + proc.call("hello") + end + "#; + let binary = mrbc_compile("to_proc_direct", code); + let mut rite = mrubyedge::rite::load(&binary).unwrap(); + let mut vm = mrubyedge::yamrb::vm::VM::open(&mut rite); + vm.run().unwrap(); + + let result = mrb_funcall(&mut vm, None, "test_to_proc_direct", &[]).unwrap(); + let result_str: String = result.as_ref().try_into().unwrap(); + assert_eq!(result_str, "HELLO"); +} + +#[test] +fn symbol_to_proc_map_to_s() { + let code = r#" + def test_to_proc_map_to_s + [1, 2, 3].map(&:to_s) + end + "#; + let binary = mrbc_compile("to_proc_map_to_s", code); + let mut rite = mrubyedge::rite::load(&binary).unwrap(); + let mut vm = mrubyedge::yamrb::vm::VM::open(&mut rite); + vm.run().unwrap(); + + let result = mrb_funcall(&mut vm, None, "test_to_proc_map_to_s", &[]).unwrap(); + let result_array: Vec> = result.as_ref().try_into().unwrap(); + let r0: String = result_array[0].as_ref().try_into().unwrap(); + let r1: String = result_array[1].as_ref().try_into().unwrap(); + let r2: String = result_array[2].as_ref().try_into().unwrap(); + assert_eq!(r0, "1"); + assert_eq!(r1, "2"); + assert_eq!(r2, "3"); +} + +#[test] +fn symbol_to_proc_keep() { + let code = r#" + def test_to_proc_keep + blk = :to_i.to_proc + a = ["1", "2", "3"].map(&blk).sum + b = ["4", "5", "6"].map(&blk).sum + c = ["7", "8", "9"].map(&blk).sum + a + b + c + end + "#; + let binary = mrbc_compile("to_proc_keep", code); + let mut rite = mrubyedge::rite::load(&binary).unwrap(); + let mut vm = mrubyedge::yamrb::vm::VM::open(&mut rite); + vm.run().unwrap(); + + let result = mrb_funcall(&mut vm, None, "test_to_proc_keep", &[]).unwrap(); + let result: i32 = result.as_ref().try_into().unwrap(); + assert_eq!(result, 45); +} + +#[test] +fn symbol_to_proc_select() { + let code = r#" + def test_to_proc_select + [nil, 1, nil, 2, 3].select(&:nil?) + end + "#; + let binary = mrbc_compile("to_proc_select", code); + let mut rite = mrubyedge::rite::load(&binary).unwrap(); + let mut vm = mrubyedge::yamrb::vm::VM::open(&mut rite); + vm.run().unwrap(); + + let result = mrb_funcall(&mut vm, None, "test_to_proc_select", &[]).unwrap(); + let result_array: Vec> = result.as_ref().try_into().unwrap(); + assert_eq!(result_array.len(), 2); + assert!(result_array[0].is_nil()); + assert!(result_array[1].is_nil()); +}