From 2fa99a73c28e97c862ab7bc261e407f32f47c74a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Jan 2026 12:52:06 +0900 Subject: [PATCH] vm: add OP_MATCHERR instruction for pattern matching errors Replace 4-instruction sequence (GETCONST + STRING + SEND + RAISEIF) with single OP_MATCHERR instruction that raises NoMatchingPatternError with "pattern not matched" message. Bump RITE binary format version from 0300 to 0400 due to opcode number shift. Co-authored-by: Claude --- include/mruby/dump.h | 4 ++-- include/mruby/ops.h | 1 + mrbgems/mruby-compiler/core/codegen.c | 15 +-------------- src/codedump.c | 3 +++ src/vm.c | 4 ++++ 5 files changed, 11 insertions(+), 16 deletions(-) diff --git a/include/mruby/dump.h b/include/mruby/dump.h index 1f587bc67..e3abf8ccb 100644 --- a/include/mruby/dump.h +++ b/include/mruby/dump.h @@ -52,13 +52,13 @@ MRB_API mrb_irep *mrb_read_irep_buf(mrb_state*, const void*, size_t); /* Binary Format Version Major:Minor */ /* Major: Incompatible to prior versions */ /* Minor: Upper-compatible to prior versions */ -#define RITE_BINARY_MAJOR_VER "03" +#define RITE_BINARY_MAJOR_VER "04" #define RITE_BINARY_MINOR_VER "00" #define RITE_BINARY_FORMAT_VER RITE_BINARY_MAJOR_VER RITE_BINARY_MINOR_VER #define RITE_COMPILER_NAME "MATZ" #define RITE_COMPILER_VERSION "0000" -#define RITE_VM_VER "0300" +#define RITE_VM_VER "0400" #define RITE_BINARY_EOF "END\0" #define RITE_SECTION_IREP_IDENT "IREP" diff --git a/include/mruby/ops.h b/include/mruby/ops.h index 05bf30fe0..9bb6f13ec 100644 --- a/include/mruby/ops.h +++ b/include/mruby/ops.h @@ -57,6 +57,7 @@ OPCODE(JMPUW, S) /* unwind_and_jump_to(a) */ OPCODE(EXCEPT, B) /* R[a] = exc */ OPCODE(RESCUE, BB) /* R[b] = R[a].isa?(R[b]) */ OPCODE(RAISEIF, B) /* raise(R[a]) if R[a] */ +OPCODE(MATCHERR, Z) /* raise NoMatchingPatternError */ OPCODE(SSEND, BBB) /* R[a] = self.send(Syms[b],R[a+1]..,R[a+n+1]:R[a+n+2]..) (c=n|k<<4) */ OPCODE(SSENDB, BBB) /* R[a] = self.send(Syms[b],R[a+1]..,R[a+n+1]:R[a+n+2]..,&R[a+n+2k+1]) */ OPCODE(SEND, BBB) /* R[a] = R[a].send(Syms[b],R[a+1]..,R[a+n+1]:R[a+n+2]..) (c=n|k<<4) */ diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 179a9ac24..bd693d420 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -6647,20 +6647,7 @@ codegen(codegen_scope *s, node *tree, int val) pop(); /* pop the value */ if (mp->raise_on_fail) { /* expr => pattern: raise NoMatchingPatternError */ - int msg_off = new_lit_cstr(s, "pattern not matched"); - int exc_reg = cursp(); - /* Get NoMatchingPatternError class */ - genop_2(s, OP_GETCONST, exc_reg, sym_idx(s, MRB_SYM_2(s->mrb, NoMatchingPatternError))); - push(); - /* Create message string */ - genop_2(s, OP_STRING, cursp(), msg_off); - push(); - /* Call NoMatchingPatternError.new(message) */ - pop(); /* pop argument */ - genop_3(s, OP_SEND, exc_reg, sym_idx(s, MRB_SYM_2(s->mrb, new)), 1); - /* Raise the exception */ - genop_1(s, OP_RAISEIF, exc_reg); - /* No push here: RAISEIF never returns, control transfers to rescue handler */ + genop_0(s, OP_MATCHERR); } else { /* expr in pattern: return false */ diff --git a/src/codedump.c b/src/codedump.c index faa75c125..d9d9ce80b 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -572,6 +572,9 @@ codedump(mrb_state *mrb, const mrb_irep *irep, FILE *out) fprintf(out, "RAISEIF\tR%d\t", a); print_lv_a(mrb, irep, a, out); break; + CASE(OP_MATCHERR, Z): + fprintf(out, "MATCHERR\n"); + break; CASE(OP_DEBUG, BBB): fprintf(out, "DEBUG\t\t%d\t%d\t%d\n", a, b, c); diff --git a/src/vm.c b/src/vm.c index ff2d63c7f..47231f187 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2167,6 +2167,10 @@ RETRY_TRY_BLOCK: NEXT; } + CASE(OP_MATCHERR, Z) { + RAISE_LIT(mrb, mrb_exc_get_id(mrb, MRB_ERROR_SYM(NoMatchingPatternError)), "pattern not matched"); + } + CASE(OP_SSEND, BBB) { regs[a] = regs[0]; }