diff --git a/include/mruby/ops.h b/include/mruby/ops.h index 9bb6f13ec..f8b91728b 100644 --- a/include/mruby/ops.h +++ b/include/mruby/ops.h @@ -57,7 +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(MATCHERR, B) /* raise NoMatchingPatternError unless R[a] */ 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 bd693d420..36a60b1d1 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -6625,14 +6625,24 @@ codegen(codegen_scope *s, node *tree, int val) } } - /* Optimize: single JMPNOT can be inverted to JMPIF, eliminating JMP */ + /* Optimize: single JMPNOT can be replaced with MATCHERR for raise_on_fail */ /* Conditions: (1) single entry in fail_pos chain, * (2) JMPNOT is immediately before current position (no code between), and * (3) the instruction is actually JMPNOT (not JMP from undefined pinned var) */ if ((int32_t)(fail_pos + 2) + (int16_t)PEEK_S(s->iseq+fail_pos) == 0 && fail_pos + 2 == s->pc && s->iseq[fail_pos - 2] == OP_JMPNOT) { - /* Single failure point - invert JMPNOT to JMPIF */ + if (mp->raise_on_fail) { + /* Single failure point with raise - replace JMPNOT with MATCHERR */ + int reg = s->iseq[fail_pos - 1]; /* Register from JMPNOT */ + s->pc = fail_pos - 2; /* Rewind past JMPNOT */ + s->lastpc = s->pc; + genop_1(s, OP_MATCHERR, reg); /* Emit MATCHERR with the register */ + s->sp = saved_sp - 1; + if (val) push(); + break; /* Pattern matching complete */ + } + /* Single failure point with 'in' pattern - invert JMPNOT to JMPIF */ s->iseq[fail_pos - 2] = OP_JMPIF; match_pos = fail_pos; } @@ -6647,7 +6657,8 @@ codegen(codegen_scope *s, node *tree, int val) pop(); /* pop the value */ if (mp->raise_on_fail) { /* expr => pattern: raise NoMatchingPatternError */ - genop_0(s, OP_MATCHERR); + genop_1(s, OP_LOADF, cursp()); /* Load false for MATCHERR */ + genop_1(s, OP_MATCHERR, cursp()); } else { /* expr in pattern: return false */ diff --git a/src/codedump.c b/src/codedump.c index d9d9ce80b..2bc3c9110 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -572,8 +572,8 @@ 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"); + CASE(OP_MATCHERR, B): + fprintf(out, "MATCHERR\tR%d\n", a); break; CASE(OP_DEBUG, BBB): diff --git a/src/vm.c b/src/vm.c index 47231f187..21d5d3907 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2167,8 +2167,11 @@ 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_MATCHERR, B) { + if (!mrb_test(regs[a])) { + RAISE_LIT(mrb, mrb_exc_get_id(mrb, MRB_ERROR_SYM(NoMatchingPatternError)), "pattern not matched"); + } + NEXT; } CASE(OP_SSEND, BBB) {