Skip to content

Commit

Permalink
Support IO#printf, Float#round, Kernel.#caller, Math#log10, Array#inj…
Browse files Browse the repository at this point in the history
…ect, #delete_if.
  • Loading branch information
sisshiki1969 committed Jan 4, 2025
1 parent e7ce3f8 commit 62cf99f
Show file tree
Hide file tree
Showing 10 changed files with 489 additions and 292 deletions.
53 changes: 38 additions & 15 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions bin/yjit-bench
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/sh

cargo install --path monoruby
cd ../yjit-bench && ./run_benchmarks.rb rubykon -e "monoruby" -e "yjit::ruby --yjit"
#cd ../yjit-bench && ./run_benchmarks.rb --harness=harness-warmup --rss fib binarytrees nbody optcarrot matmul nqueens sudoku bedcov -e "monoruby" -e "yjit::ruby --yjit"
#cd ../yjit-bench && ./run_benchmarks.rb rubykon -e "monoruby" -e "yjit::ruby --yjit"
cd ../yjit-bench && ./run_benchmarks.rb --rss fib binarytrees rubykon nbody optcarrot matmul nqueens sudoku bedcov -e "monoruby" -e "yjit::ruby --yjit"
#cd ../yjit-bench && ./run_benchmarks.rb --harness=harness-warmup --rss -e "monoruby" -e "yjit::ruby --yjit"
65 changes: 58 additions & 7 deletions monoruby/src/builtins/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub(super) fn init(globals: &mut Globals) {
globals.define_builtin_func(ARRAY_CLASS, "fill", fill, 1);
globals.define_builtin_func(ARRAY_CLASS, "drop", drop, 1);
globals.define_builtin_func_rest(ARRAY_CLASS, "zip", zip);
globals.define_builtin_funcs_with(ARRAY_CLASS, "inject", &["reduce"], inject, 0, 1, false);
globals.define_builtin_funcs_with(ARRAY_CLASS, "inject", &["reduce"], inject, 0, 2, false);
globals.define_builtin_func_with(ARRAY_CLASS, "join", join, 0, 1, false);
globals.define_builtin_func_with(ARRAY_CLASS, "first", first, 0, 1, false);
globals.define_builtin_func_with(ARRAY_CLASS, "last", last, 0, 1, false);
Expand All @@ -59,6 +59,7 @@ pub(super) fn init(globals: &mut Globals) {
globals.define_builtin_funcs(ARRAY_CLASS, "filter", &["select", "find_all"], filter, 0);
globals.define_builtin_funcs(ARRAY_CLASS, "filter!", &["select!"], filter_, 0);
globals.define_builtin_func(ARRAY_CLASS, "reject!", reject_, 0);
globals.define_builtin_func(ARRAY_CLASS, "delete_if", delete_if, 0);
globals.define_builtin_func(ARRAY_CLASS, "reject", reject, 0);
globals.define_builtin_func(ARRAY_CLASS, "sort", sort, 0);
globals.define_builtin_func(ARRAY_CLASS, "sort!", sort_, 0);
Expand Down Expand Up @@ -705,20 +706,41 @@ fn zip(vm: &mut Executor, globals: &mut Globals, lfp: Lfp) -> Result<Value> {
/// ### Array#inject
///
/// - inject(init = self.first) {|result, item| ... } -> object
/// - inject(sym) -> object
/// - inject(init, sym) -> object
/// - reduce(init = self.first) {|result, item| ... } -> object
/// - reduce(sym) -> object
/// - reduce(init, sym) -> object
///
/// [https://docs.ruby-lang.org/ja/latest/method/Enumerable/i/inject.html]
#[monoruby_builtin]
fn inject(vm: &mut Executor, globals: &mut Globals, lfp: Lfp) -> Result<Value> {
let bh = lfp.expect_block()?;
let self_ = lfp.self_val().as_array();
let mut iter = self_.iter().cloned();
let res = if lfp.try_arg(0).is_none() {
iter.next().unwrap_or_default()
if let Some(bh) = lfp.block() {
let res = if lfp.try_arg(0).is_none() {
iter.next().unwrap_or_default()
} else {
lfp.arg(0)
};
vm.invoke_block_fold1(globals, bh, iter, res)
} else {
lfp.arg(0)
};
vm.invoke_block_fold1(globals, bh, iter, res)
let (sym, mut res) = if let Some(arg0) = lfp.try_arg(0) {
if let Some(arg1) = lfp.try_arg(1) {
(arg1.expect_symbol_or_string()?, arg0)
} else {
let sym = arg0.expect_symbol_or_string()?;
let res = iter.next().unwrap_or_default();
(sym, res)
}
} else {
return Err(MonorubyErr::argumenterr("wrong number of arguments"));
};
for v in iter {
res = vm.invoke_method_inner(globals, sym, res, &[v], None)?;
}
Ok(res)
}
}

///
Expand Down Expand Up @@ -1141,6 +1163,28 @@ fn reject_(vm: &mut Executor, globals: &mut Globals, lfp: Lfp) -> Result<Value>
}
}

///
/// ### Array#delete_if
///
/// - delete_if {|x| ... } -> self
/// - delete_if -> Enumerator
///
/// [https://docs.ruby-lang.org/ja/latest/method/Array/i/delete_if.html]
#[monoruby_builtin]
fn delete_if(vm: &mut Executor, globals: &mut Globals, lfp: Lfp) -> Result<Value> {
let mut ary = lfp.self_val().as_array();
if let Some(bh) = lfp.block() {
let data = vm.get_block_data(globals, bh)?;
ary.retain(|v| {
vm.invoke_block(globals, &data, &[*v])
.map(|res| !res.as_bool())
})?;
Ok(lfp.self_val())
} else {
vm.generate_enumerator(IdentId::get_id("delete_if"), lfp.self_val(), vec![])
}
}

///
/// ### Enumerable#group_by
///
Expand Down Expand Up @@ -2174,6 +2218,8 @@ mod tests {
run_test(r##"[2, 3, 4, 5].inject(0) {|result, item| result + item }"##);
run_test(r##"[2, 3, 4, 5].inject {|result, item| result + item }"##);
run_test(r##"[2, 3, 4, 5].inject(5) {|result, item| result + item**2 }"##);
run_test(r##"[1, 2, 3, 4, 5].inject(:+)"##);
run_test(r##"[1, 2, 3, 4, 5].inject(10, :+)"##);
}

#[test]
Expand Down Expand Up @@ -2364,7 +2410,12 @@ mod tests {
run_test(r##"[1,2,3,4,5].reject(&:even?)"##);
run_test(r##"a=[1,2,3,4,5]; a.reject! { |num| num.even? }; a"##);
run_test(r##"a=[1,2,3,4,5]; a.reject! { true }; a"##);
run_test(r##"a=[1,2,3,4,5]; a.reject! { false }; a"##);
run_test(r##"a=[1,2,3,4,5]; a.reject!(&:even?); a"##);
run_test(r##"a=[1,2,3,4,5]; a.delete_if { |num| num.even? }; a"##);
run_test(r##"a=[1,2,3,4,5]; a.delete_if { true }; a"##);
run_test(r##"a=[1,2,3,4,5]; a.delete_if { false }; a"##);
run_test(r##"a=[1,2,3,4,5]; a.delete_if(&:even?); a"##);
run_test(
r##"
a = %w{ a b c d e f }
Expand Down
23 changes: 23 additions & 0 deletions monoruby/src/builtins/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub(super) fn init(globals: &mut Globals) {
globals.define_builtin_func(IO_CLASS, "<<", shl, 1);
globals.define_builtin_func_with(IO_CLASS, "puts", puts, 0, 0, true);
globals.define_builtin_func_with(IO_CLASS, "print", print, 0, 0, true);
globals.define_builtin_func_with(IO_CLASS, "printf", printf, 1, 1, true);
globals.define_builtin_func(IO_CLASS, "gets", gets, 0);
globals.define_builtin_funcs(IO_CLASS, "isatty", &["tty?"], isatty, 0);
globals.define_builtin_func(IO_CLASS, "sync", sync, 0);
Expand Down Expand Up @@ -96,6 +97,25 @@ fn print(_vm: &mut Executor, globals: &mut Globals, lfp: Lfp) -> Result<Value> {
Ok(Value::nil())
}

///
/// ### IO#printf
///
/// - printf(format, *arg) -> nil
///
/// [https://docs.ruby-lang.org/ja/latest/method/IO/i/printf.html]
#[monoruby_builtin]
fn printf(_vm: &mut Executor, globals: &mut Globals, lfp: Lfp) -> Result<Value> {
let mut self_ = lfp.self_val();
let io = self_.as_io_inner_mut();
let format_str = lfp.arg(0).expect_string()?;
let args = lfp.arg(1).as_array();

let buf = globals.format_by_args(&format_str, &args)?;
io.write(buf.as_bytes())?;

Ok(Value::nil())
}

fn io_writeline(globals: &Globals, io: &mut IoInner, v: Value) -> Result<()> {
if let Some(s) = v.is_bytes() {
io.write(s)?;
Expand Down Expand Up @@ -249,6 +269,9 @@ mod tests {
r#"
$stdout << "a"
$stdout << 5
$stdout.puts 100
$stdout.print 100
$stdout.printf("%b%10.5f", 100, 3.14)
File.open("/dev/null", "w") << 5
File.open("/dev/null", "w+") << 5
$stdin.sync
Expand Down
47 changes: 43 additions & 4 deletions monoruby/src/builtins/kernel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub(super) fn init(globals: &mut Globals) -> Module {
);
globals.define_builtin_module_func(kernel_class, "__dir__", dir_, 0);
globals.define_builtin_func(kernel_class, "__assert", assert, 2);
globals.define_builtin_func_with(kernel_class, "caller", caller, 0, 1, false);
globals.define_builtin_func(kernel_class, "__dump", dump, 0);
globals.define_builtin_func(kernel_class, "__check_stack", check_stack, 0);
globals.define_builtin_func(kernel_class, "__instance_ty", instance_ty, 0);
Expand Down Expand Up @@ -304,6 +305,44 @@ fn p(_vm: &mut Executor, globals: &mut Globals, lfp: Lfp) -> Result<Value> {
})
}

///
/// ### Kernel.#caller
///
/// - caller(start = 1) -> [String] | nil
/// - [NOT SUPPORTED] caller(start, length) -> [String] | nil
/// - [NOT SUPPORTED] caller(range) -> [String] | nil
///
/// [https://docs.ruby-lang.org/ja/latest/method/Kernel/m/caller.html]
#[monoruby_builtin]
fn caller(vm: &mut Executor, globals: &mut Globals, lfp: Lfp) -> Result<Value> {
let mut cfp = vm.cfp();
let mut v = Vec::new();
let level = if let Some(arg0) = lfp.try_arg(0) {
arg0.coerce_to_i64()? as usize + 1
} else {
2
};
for i in 0..16 {
let prev_cfp = cfp.prev();
if i >= level {
let func_id = cfp.lfp().meta().func_id();
if let Some(iseq) = globals.store[func_id].is_iseq() {
let loc = globals.store[iseq].get_location();
let desc = globals.store.func_description(func_id);
v.push(Value::string_from_vec(
format!("{loc}:in `{desc}`").into_bytes(),
));
}
}
if let Some(prev_cfp) = prev_cfp {
cfp = prev_cfp;
} else {
break;
}
}
Ok(Value::array_from_vec(v))
}

#[monoruby_builtin]
fn assert(_vm: &mut Executor, globals: &mut Globals, lfp: Lfp) -> Result<Value> {
let expected = lfp.arg(0);
Expand Down Expand Up @@ -1010,13 +1049,13 @@ mod tests {
}

#[test]
#[ignore]
fn kernel() {
run_test_no_result_check("sleep 1");
run_test_error("abort 1");
run_test_no_result_check("exit");
run_test_no_result_check("exit 0");
//run_test_error("abort 1");
//run_test_no_result_check("exit");
//run_test_no_result_check("exit 0");
run_test_no_result_check("__dir__");
run_test_no_result_check("caller(1)");
}

#[test]
Expand Down
Loading

0 comments on commit 62cf99f

Please sign in to comment.