diff options
-rw-r--r-- | eval.c | 17 | ||||
-rw-r--r-- | include/ruby/internal/intern/proc.h | 334 |
2 files changed, 317 insertions, 34 deletions
@@ -983,23 +983,6 @@ rb_rescue(VALUE (* b_proc)(VALUE), VALUE data1, (VALUE)0); } -/*! Protects a function call from potential global escapes from the function. - * - * Such global escapes include exceptions, \c Kernel\#throw, \c break in - * an iterator, for example. - * It first calls the function func with arg as the argument. - * If no exception occurred during func, it returns the result of func and - * *state is zero. - * Otherwise, it returns Qnil and sets *state to nonzero. - * If state is NULL, it is not set in both cases. - * - * You have to clear the error info with rb_set_errinfo(Qnil) when - * ignoring the caught exception. - * \ingroup exception - * \sa rb_rescue - * \sa rb_rescue2 - * \sa rb_ensure - */ VALUE rb_protect(VALUE (* proc) (VALUE), VALUE data, int *pstate) { diff --git a/include/ruby/internal/intern/proc.h b/include/ruby/internal/intern/proc.h index fa193b0470..b8c3c5e146 100644 --- a/include/ruby/internal/intern/proc.h +++ b/include/ruby/internal/intern/proc.h @@ -27,26 +27,326 @@ RBIMPL_SYMBOL_EXPORT_BEGIN() /* proc.c */ + +/** + * Constructs a Proc object from implicitly passed components. When a ruby + * method is called with a block, that block is not explicitly passed around + * using C level function parameters. This function gathers all the necessary + * info to turn them into a Ruby level instance of ::rb_cProc. + * + * @exception rb_eArgError There is no passed block. + * @return An instance of ::rb_cProc. + */ VALUE rb_block_proc(void); + +/** + * Identical to rb_proc_new(), except it returns a lambda. + * + * @exception rb_eArgError There is no passed block. + * @return An instance of ::rb_cProc. + */ VALUE rb_block_lambda(void); -VALUE rb_proc_new(rb_block_call_func_t, VALUE); -VALUE rb_obj_is_proc(VALUE); -VALUE rb_proc_call(VALUE, VALUE); -VALUE rb_proc_call_kw(VALUE, VALUE, int); -VALUE rb_proc_call_with_block(VALUE, int argc, const VALUE *argv, VALUE); -VALUE rb_proc_call_with_block_kw(VALUE, int argc, const VALUE *argv, VALUE, int); -int rb_proc_arity(VALUE); -VALUE rb_proc_lambda_p(VALUE); + +/** + * This is an rb_iterate() + rb_block_proc() combo. + * + * ```CXX + * VALUE + * my_own_iterator(RB_BLOCK_CALL_FUNC_ARGLIST(y, c)) + * { + * const auto plus = rb_intern("+"); + * return rb_funcall(c, plus, 1, y); + * } + * + * VALUE + * my_own_method(VALUE self) + * { + * return rb_proc_new(my_own_iterator, self); + * } + * ``` + * + * @param[in] func A backend function of a proc. + * @param[in] callback_arg Passed to `func`'s callback_arg. + * @return A C-backended proc object. + * + */ +VALUE rb_proc_new(rb_block_call_func_t func, VALUE callback_arg); + +/** + * Queries if the given object is a proc. + * + * @note This is about the object's data structure, not its class etc. + * @param[in] recv Object in question. + * @retval RUBY_Qtrue It is a proc. + * @retval RUBY_Qfalse Otherwise. + */ +VALUE rb_obj_is_proc(VALUE recv); + +/** + * Evaluates the passed proc with the passed arguments. + * + * @param[in] recv The proc to call. + * @param[in] args An instance of ::RArray which is the arguments. + * @exception rb_eException Any exceptions happen inside. + * @return What the proc evaluates to. + */ +VALUE rb_proc_call(VALUE recv, VALUE args); + +/** + * Identical to rb_proc_call(), except you can specify how to handle the last + * element of the given array. + * + * @param[in] recv The proc to call. + * @param[in] args An instance of ::RArray which is the arguments. + * @param[in] kw_splat Handling of keyword parameters: + * - RB_NO_KEYWORDS `args`' last is not a keyword argument. + * - RB_PASS_KEYWORDS `args`' last is a keyword argument. + * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block. + * @exception rb_eException Any exceptions happen inside. + * @return What the proc evaluates to. + */ +VALUE rb_proc_call_kw(VALUE recv, VALUE args, int kw_splat); + +/** + * Identical to rb_proc_call(), except you can additionally pass another proc + * object, as a block. Nowadays procs can take blocks: + * + * ```ruby + * l = -> (positional, optional=nil, *rest, kwarg:, **kwrest, &block) { + * # ... how can we pass this `&block`? ^^^^^^ + * } + * ``` + * + * And this function is to pass one to such procs. + * + * @param[in] recv The proc to call. + * @param[in] argc Number of arguments. + * @param[in] argv Arbitrary number of proc arguments. + * @param[in] proc Proc as a passed block. + * @exception rb_eException Any exceptions happen inside. + * @return What the proc evaluates to. + */ +VALUE rb_proc_call_with_block(VALUE recv, int argc, const VALUE *argv, VALUE proc); + +/** + * Identical to rb_proc_call_with_block(), except you can specify how to handle + * the last element of the given array. It can also be seen as a routine + * identical to rb_proc_call_kw(), except you can additionally pass another + * proc object as a block. + * + * @param[in] recv The proc to call. + * @param[in] argc Number of arguments. + * @param[in] argv Arbitrary number of proc arguments. + * @param[in] proc Proc as a passed block. + * @param[in] kw_splat Handling of keyword parameters: + * - RB_NO_KEYWORDS `args`' last is not a keyword argument. + * - RB_PASS_KEYWORDS `args`' last is a keyword argument. + * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block. + * @exception rb_eException Any exceptions happen inside. + * @return What the proc evaluates to. + */ +VALUE rb_proc_call_with_block_kw(VALUE recv, int argc, const VALUE *argv, VALUE proc, int kw_splat); + +/** + * Queries the number of mandatory arguments of the given Proc. If its block + * is declared to take no arguments, returns `0`. If the block is known to + * take exactly `n` arguments, returns `n`. If the block has optional + * arguments, returns `-n-1`, where `n` is the number of mandatory arguments, + * with the exception for blocks that are not lambdas and have only a finite + * number of optional arguments; in this latter case, returns `n`. Keyword + * arguments will be considered as a single additional argument, that argument + * being mandatory if any keyword argument is mandatory. + * + * @param[in] recv Target Proc object. + * @retval 0 It takes no arguments. + * @retval >0 It takes exactly this number of arguments. + * @retval <0 It takes optional arguments. + */ +int rb_proc_arity(VALUE recv); + +/** + * Queries if the given object is a lambda. Instances of ::rb_cProc are either + * lambda or proc. They differ in several points. This function can + * distinguish them without actually evaluating their contents. + * + * @param[in] recv Target proc object. + * @retval RUBY_Qtrue It is a lambda. + * @retval RUBY_Qfalse Otherwise. + */ +VALUE rb_proc_lambda_p(VALUE recv); + +/** + * Snapshots the current execution context and turn it into an instance of + * ::rb_cBinding. + * + * @return An instance of ::rb_cBinding. + */ VALUE rb_binding_new(void); -VALUE rb_obj_method(VALUE, VALUE); -VALUE rb_obj_is_method(VALUE); -VALUE rb_method_call(int, const VALUE*, VALUE); -VALUE rb_method_call_kw(int, const VALUE*, VALUE, int); -VALUE rb_method_call_with_block(int, const VALUE *, VALUE, VALUE); -VALUE rb_method_call_with_block_kw(int, const VALUE *, VALUE, VALUE, int); -int rb_mod_method_arity(VALUE, ID); -int rb_obj_method_arity(VALUE, ID); -VALUE rb_protect(VALUE (*)(VALUE), VALUE, int*); + +/** + * Creates a method object. A method object is a proc-like object that you can + * "call". Note that a method object snapshots the method at the time the + * object is created: + * + * ```ruby + * class Foo + * def foo + * return 1 + * end + * end + * + * obj = Foo.new.method(:foo) + * + * class Foo + * def foo + * return 2 + * end + * end + * + * obj.call # => 1, not 2. + * ``` + * + * @param[in] recv Receiver of the method. + * @param[in] mid Method name, in either String or Symbol. + * @exception rb_eNoMethodError No such method. + * @return An instance of ::rb_cMethod. + */ +VALUE rb_obj_method(VALUE recv, VALUE mid); + +/** + * Queries if the given object is a method. + * + * @note This is about the object's data structure, not its class etc. + * @param[in] recv Object in question. + * @retval RUBY_Qtrue It is a method. + * @retval RUBY_Qfalse Otherwise. + */ +VALUE rb_obj_is_method(VALUE recv); + +/** + * Evaluates the passed method with the passed arguments. + * + * @param[in] argc Number of objects of `argv`. + * @param[in] argv Arbitrary number of method arguments. + * @param[in] recv The method object to call. + * @exception rb_eTypeError `recv` is not a method. + * @exception rb_eException Any exceptions happen inside. + * @return What the method returns. + */ +VALUE rb_method_call(int argc, const VALUE *argv, VALUE recv); + +/** + * Identical to rb_method_call(), except you can specify how to handle the last + * element of the given array. + * + * @param[in] argc Number of objects of `argv`. + * @param[in] argv Arbitrary number of method arguments. + * @param[in] recv The method object to call. + * @param[in] kw_splat Handling of keyword parameters: + * - RB_NO_KEYWORDS `args`' last is not a keyword argument. + * - RB_PASS_KEYWORDS `args`' last is a keyword argument. + * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block. + * @exception rb_eTypeError `recv` is not a method. + * @exception rb_eException Any exceptions happen inside. + * @return What the method returns. + */ +VALUE rb_method_call_kw(int argc, const VALUE *argv, VALUE recv, int kw_splat); + +/** + * Identical to rb_proc_call(), except you can additionally pass a proc as a + * block. + * + * @param[in] argc Number of objects of `argv`. + * @param[in] argv Arbitrary number of method arguments. + * @param[in] recv The method object to call. + * @param[in] proc Proc as a passed block. + * @exception rb_eTypeError `recv` is not a method. + * @exception rb_eException Any exceptions happen inside. + * @return What the method returns. + */ +VALUE rb_method_call_with_block(int argc, const VALUE *argv, VALUE recv, VALUE proc); + +/** + * Identical to rb_method_call_with_block(), except you can specify how to + * handle the last element of the given array. It can also be seen as a + * routine identical to rb_method_call_kw(), except you can additionally pass + * another proc object as a block. + * + * @param[in] argc Number of objects of `argv`. + * @param[in] argv Arbitrary number of method arguments. + * @param[in] recv The method object to call. + * @param[in] proc Proc as a passed block. + * @param[in] kw_splat Handling of keyword parameters: + * - RB_NO_KEYWORDS `args`' last is not a keyword argument. + * - RB_PASS_KEYWORDS `args`' last is a keyword argument. + * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block. + * @exception rb_eTypeError `recv` is not a method. + * @exception rb_eException Any exceptions happen inside. + * @return What the method returns. + */ +VALUE rb_method_call_with_block_kw(int argc, const VALUE *argv, VALUE recv, VALUE proc, int kw_splat); + +/** + * Queries the number of mandatory arguments of the method defined in the given + * module. If it is declared to take no arguments, returns `0`. If it takes + * exactly `n` arguments, returns `n`. If it has optional arguments, returns + * `-n-1`, where `n` is the number of mandatory arguments. Keyword arguments + * will be considered as a single additional argument, that argument being + * mandatory if any keyword argument is mandatory. + * + * @param[in] mod Namespace to search a method for. + * @param[in] mid Method id. + * @retval 0 It takes no arguments. + * @retval >0 It takes exactly this number of arguments. + * @retval <0 It takes optional arguments. + */ +int rb_mod_method_arity(VALUE mod, ID mid); + +/** + * Identical to rb_mod_method_arity(), except it searches for singleton methods + * rather than instance methods. + * + * @param[in] obj Object to search for a singleton method. + * @param[in] mid Method id. + * @retval 0 It takes no arguments. + * @retval >0 It takes exactly this number of arguments. + * @retval <0 It takes optional arguments. + */ +int rb_obj_method_arity(VALUE obj, ID mid); + +/* eval.c */ + +RBIMPL_ATTR_NONNULL((1)) +/** + * Protects a function call from potential global escapes from the function. + * Such global escapes include exceptions, `throw`, `break`, for example. + * + * It first calls the function func with `args` as the argument. If no global + * escape occurred during the function, it returns the result and `*state` is + * zero. Otherwise, it returns ::RUBY_Qnil and sets `*state` to nonzero. If + * `state` is `NULL`, it is not set in both cases. + * + * @param[in] func A function that potentially escapes globally. + * @param[in] args Passed as-is to `func`. + * @param[out] state State of execution. + * @return What `func` returns, or an undefined value when it did not + * return. + * @post `*state` is set to zero if succeeded. Nonzero otherwise. + * @warning You have to clear the error info with `rb_set_errinfo(Qnil)` if + * you decide to ignore the caught exception. + * @see rb_eval_string_protect() + * @see rb_load_protect() + * + * @internal + * + * The "undefined value" described above is in fact ::RUBY_Qnil for now. But + * @shyouhei doesn't think that we would never change that. + * + * Though not a part of our public API, `state` is in fact an + * enum ruby_tag_type. You can see the potential "nonzero" values by looking + * at vm_core.h. + */ +VALUE rb_protect(VALUE (*func)(VALUE args), VALUE args, int *state); RBIMPL_SYMBOL_EXPORT_END() |