mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-catch: add comprehensive call-seq documentation and helper function comments
Added complete call-seq documentation for catch/throw functionality across both Ruby and C implementations: - Class documentation: explains exception raised for unmatched throws - initialize: constructor with tag and value parameters, creates error message with proper tag inspection and stores thrown values for debugging - throw: transfers control to matching catch block with optional return value, raises UncaughtThrowError if no matching catch found, supports both single tag and tag+value forms with comprehensive usage examples - find_catcher: searches call stack for matching catch block by comparing tags using mrb_obj_eq, returns call stack index or 0 if not found - catch_syms: pre-defined symbols (Object, new, call) used by catch bytecode implementation for efficient symbol lookup - catch_iseq: bytecode instruction sequence implementing catch method logic, handles default tag creation (Object.new) and block parameter passing - catch_irep: instruction representation containing bytecode metadata for catch method execution - catch_proc: procedure object used to identify catch blocks in call stack during throw operations, marked with proper GC and scope flags - mrb_mruby_catch_gem_init: defines catch and throw as private methods in Kernel module, initializes symbols and sets up bytecode procedure - mrb_mruby_catch_gem_final: cleanup function (currently no-op as implementation uses static data structures) Co-authored-by: Atlassian Rovo Dev
This commit is contained in:
@@ -1,5 +1,26 @@
|
||||
#
|
||||
# Exception raised when a throw is executed without a corresponding catch.
|
||||
# This error contains the tag and value that were thrown.
|
||||
#
|
||||
class UncaughtThrowError < ArgumentError
|
||||
attr_reader :tag, :value
|
||||
# The tag that was thrown
|
||||
attr_reader :tag
|
||||
# The value that was thrown with the tag
|
||||
attr_reader :value
|
||||
|
||||
#
|
||||
# call-seq:
|
||||
# UncaughtThrowError.new(tag, value) -> exception
|
||||
#
|
||||
# Creates a new UncaughtThrowError with the given tag and value.
|
||||
# The tag is the symbol or object that was thrown, and value is
|
||||
# the associated value.
|
||||
#
|
||||
# error = UncaughtThrowError.new(:done, "finished")
|
||||
# error.tag #=> :done
|
||||
# error.value #=> "finished"
|
||||
# error.message #=> "uncaught throw :done"
|
||||
#
|
||||
def initialize(tag, value)
|
||||
@tag = tag
|
||||
@value = value
|
||||
|
||||
@@ -6,11 +6,17 @@
|
||||
#include <mruby/opcode.h>
|
||||
#include <mruby/presym.h>
|
||||
|
||||
/* Pre-defined symbols used by catch implementation */
|
||||
MRB_PRESYM_DEFINE_VAR_AND_INITER(catch_syms, 3, MRB_SYM(Object), MRB_SYM(new), MRB_SYM(call))
|
||||
|
||||
/*
|
||||
* Bytecode implementation of catch method:
|
||||
* def catch(r1 = Object.new, &r2)
|
||||
* r2.call(r1)
|
||||
* end
|
||||
*
|
||||
* This creates a default tag (Object.new) if none provided, then calls
|
||||
* the block with the tag as argument.
|
||||
*/
|
||||
static const mrb_code catch_iseq[] = {
|
||||
OP_ENTER, 0x00, 0x20, 0x01, // 000 ENTER 0:1:0:0:0:0:1 (0x2001)
|
||||
@@ -29,6 +35,8 @@ static const mrb_code catch_iseq[] = {
|
||||
OP_SEND, 0x02, 0x02, 0x01, // 023 SEND R2 :call n=1
|
||||
OP_RETURN, 0x02, // 027 RETURN R2
|
||||
};
|
||||
|
||||
/* Instruction representation for catch method bytecode */
|
||||
static const mrb_irep catch_irep = {
|
||||
3,5,0,
|
||||
MRB_IREP_STATIC,catch_iseq,
|
||||
@@ -37,12 +45,15 @@ static const mrb_irep catch_irep = {
|
||||
NULL,
|
||||
sizeof(catch_iseq),0,3,0,0
|
||||
};
|
||||
|
||||
/* Procedure object for catch method - used to identify catch blocks in call stack */
|
||||
mrb_alignas(8)
|
||||
static const struct RProc catch_proc = {
|
||||
NULL, NULL, MRB_TT_PROC, MRB_GC_RED, MRB_OBJ_IS_FROZEN, MRB_PROC_SCOPE | MRB_PROC_STRICT,
|
||||
{ &catch_irep }, NULL, { NULL }
|
||||
};
|
||||
|
||||
/* Helper function to find a matching catch block in the call stack */
|
||||
static size_t
|
||||
find_catcher(mrb_state *mrb, mrb_value tag)
|
||||
{
|
||||
@@ -59,6 +70,30 @@ find_catcher(mrb_state *mrb, mrb_value tag)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* throw(tag) -> obj
|
||||
* throw(tag, obj) -> obj
|
||||
*
|
||||
* Transfers control to the end of the active catch block waiting for tag.
|
||||
* Raises UncaughtThrowError if there is no catch block for the tag. The
|
||||
* optional second parameter supplies a return value for the catch block,
|
||||
* which otherwise defaults to nil.
|
||||
*
|
||||
* def routine(n)
|
||||
* puts n
|
||||
* throw :done if n <= 0
|
||||
* routine(n-1)
|
||||
* end
|
||||
*
|
||||
* catch(:done) { routine(3) }
|
||||
* 3
|
||||
* 2
|
||||
* 1
|
||||
* 0
|
||||
*
|
||||
* catch(:done) { throw :done, "hello" } #=> "hello"
|
||||
*/
|
||||
static mrb_value
|
||||
throw_m(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
@@ -80,6 +115,17 @@ throw_m(mrb_state *mrb, mrb_value self)
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
/*
|
||||
* Initializes the mruby-catch gem by defining catch and throw methods.
|
||||
*
|
||||
* - catch: defined using the pre-compiled bytecode procedure for efficiency,
|
||||
* marked as private method in Kernel module
|
||||
* - throw: defined as a regular C method that searches for matching catch blocks,
|
||||
* also marked as private method in Kernel module
|
||||
*
|
||||
* Both methods are added to the Kernel module, making them available globally
|
||||
* as private methods that can be called without a receiver.
|
||||
*/
|
||||
void
|
||||
mrb_mruby_catch_gem_init(mrb_state *mrb)
|
||||
{
|
||||
@@ -93,6 +139,10 @@ mrb_mruby_catch_gem_init(mrb_state *mrb)
|
||||
mrb_define_private_method_id(mrb, mrb->kernel_module, MRB_SYM(throw), throw_m, MRB_ARGS_ARG(1,1));
|
||||
}
|
||||
|
||||
/*
|
||||
* Finalizes the mruby-catch gem. Currently no cleanup is required
|
||||
* as the catch/throw implementation uses static data structures.
|
||||
*/
|
||||
void
|
||||
mrb_mruby_catch_gem_final(mrb_state *mrb)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user